| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 } | 71 } |
| 72 | 72 |
| 73 void EmitJumpIfSmi(Register reg, | 73 void EmitJumpIfSmi(Register reg, |
| 74 Label* target, | 74 Label* target, |
| 75 Label::Distance distance = Label::kFar) { | 75 Label::Distance distance = Label::kFar) { |
| 76 __ test(reg, Immediate(kSmiTagMask)); | 76 __ test(reg, Immediate(kSmiTagMask)); |
| 77 EmitJump(carry, target, distance); // Never taken before patched. | 77 EmitJump(carry, target, distance); // Never taken before patched. |
| 78 } | 78 } |
| 79 | 79 |
| 80 void EmitPatchInfo() { | 80 void EmitPatchInfo() { |
| 81 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_); | 81 if (patch_site_.is_bound()) { |
| 82 ASSERT(is_int8(delta_to_patch_site)); | 82 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_); |
| 83 __ test(eax, Immediate(delta_to_patch_site)); | 83 ASSERT(is_int8(delta_to_patch_site)); |
| 84 __ test(eax, Immediate(delta_to_patch_site)); |
| 84 #ifdef DEBUG | 85 #ifdef DEBUG |
| 85 info_emitted_ = true; | 86 info_emitted_ = true; |
| 86 #endif | 87 #endif |
| 88 } else { |
| 89 __ nop(); // Signals no inlined code. |
| 90 } |
| 87 } | 91 } |
| 88 | 92 |
| 89 bool is_bound() const { return patch_site_.is_bound(); } | |
| 90 | |
| 91 private: | 93 private: |
| 92 // jc will be patched with jz, jnc will become jnz. | 94 // jc will be patched with jz, jnc will become jnz. |
| 93 void EmitJump(Condition cc, Label* target, Label::Distance distance) { | 95 void EmitJump(Condition cc, Label* target, Label::Distance distance) { |
| 94 ASSERT(!patch_site_.is_bound() && !info_emitted_); | 96 ASSERT(!patch_site_.is_bound() && !info_emitted_); |
| 95 ASSERT(cc == carry || cc == not_carry); | 97 ASSERT(cc == carry || cc == not_carry); |
| 96 __ bind(&patch_site_); | 98 __ bind(&patch_site_); |
| 97 __ j(cc, target, distance); | 99 __ j(cc, target, distance); |
| 98 } | 100 } |
| 99 | 101 |
| 100 MacroAssembler* masm_; | 102 MacroAssembler* masm_; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 114 // o edi: the JS function object being called (ie, ourselves) | 116 // o edi: the JS function object being called (ie, ourselves) |
| 115 // o esi: our context | 117 // o esi: our context |
| 116 // o ebp: our caller's frame pointer | 118 // o ebp: our caller's frame pointer |
| 117 // o esp: stack pointer (pointing to return address) | 119 // o esp: stack pointer (pointing to return address) |
| 118 // | 120 // |
| 119 // The function builds a JS frame. Please see JavaScriptFrameConstants in | 121 // The function builds a JS frame. Please see JavaScriptFrameConstants in |
| 120 // frames-ia32.h for its layout. | 122 // frames-ia32.h for its layout. |
| 121 void FullCodeGenerator::Generate(CompilationInfo* info) { | 123 void FullCodeGenerator::Generate(CompilationInfo* info) { |
| 122 ASSERT(info_ == NULL); | 124 ASSERT(info_ == NULL); |
| 123 info_ = info; | 125 info_ = info; |
| 126 scope_ = info->scope(); |
| 124 SetFunctionPosition(function()); | 127 SetFunctionPosition(function()); |
| 125 Comment cmnt(masm_, "[ function compiled by full code generator"); | 128 Comment cmnt(masm_, "[ function compiled by full code generator"); |
| 126 | 129 |
| 127 #ifdef DEBUG | 130 #ifdef DEBUG |
| 128 if (strlen(FLAG_stop_at) > 0 && | 131 if (strlen(FLAG_stop_at) > 0 && |
| 129 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 132 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
| 130 __ int3(); | 133 __ int3(); |
| 131 } | 134 } |
| 132 #endif | 135 #endif |
| 133 | 136 |
| 134 // Strict mode functions need to replace the receiver with undefined | 137 // Strict mode functions and builtins need to replace the receiver |
| 135 // when called as functions (without an explicit receiver | 138 // with undefined when called as functions (without an explicit |
| 136 // object). ecx is zero for method calls and non-zero for function | 139 // receiver object). ecx is zero for method calls and non-zero for |
| 137 // calls. | 140 // function calls. |
| 138 if (info->is_strict_mode()) { | 141 if (info->is_strict_mode() || info->is_native()) { |
| 139 Label ok; | 142 Label ok; |
| 140 __ test(ecx, Operand(ecx)); | 143 __ test(ecx, Operand(ecx)); |
| 141 __ j(zero, &ok, Label::kNear); | 144 __ j(zero, &ok, Label::kNear); |
| 142 // +1 for return address. | 145 // +1 for return address. |
| 143 int receiver_offset = (scope()->num_parameters() + 1) * kPointerSize; | 146 int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize; |
| 144 __ mov(Operand(esp, receiver_offset), | 147 __ mov(Operand(esp, receiver_offset), |
| 145 Immediate(isolate()->factory()->undefined_value())); | 148 Immediate(isolate()->factory()->undefined_value())); |
| 146 __ bind(&ok); | 149 __ bind(&ok); |
| 147 } | 150 } |
| 148 | 151 |
| 149 __ push(ebp); // Caller's frame pointer. | 152 __ push(ebp); // Caller's frame pointer. |
| 150 __ mov(ebp, esp); | 153 __ mov(ebp, esp); |
| 151 __ push(esi); // Callee's context. | 154 __ push(esi); // Callee's context. |
| 152 __ push(edi); // Callee's JS Function. | 155 __ push(edi); // Callee's JS Function. |
| 153 | 156 |
| 154 { Comment cmnt(masm_, "[ Allocate locals"); | 157 { Comment cmnt(masm_, "[ Allocate locals"); |
| 155 int locals_count = scope()->num_stack_slots(); | 158 int locals_count = info->scope()->num_stack_slots(); |
| 156 if (locals_count == 1) { | 159 if (locals_count == 1) { |
| 157 __ push(Immediate(isolate()->factory()->undefined_value())); | 160 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 158 } else if (locals_count > 1) { | 161 } else if (locals_count > 1) { |
| 159 __ mov(eax, Immediate(isolate()->factory()->undefined_value())); | 162 __ mov(eax, Immediate(isolate()->factory()->undefined_value())); |
| 160 for (int i = 0; i < locals_count; i++) { | 163 for (int i = 0; i < locals_count; i++) { |
| 161 __ push(eax); | 164 __ push(eax); |
| 162 } | 165 } |
| 163 } | 166 } |
| 164 } | 167 } |
| 165 | 168 |
| 166 bool function_in_register = true; | 169 bool function_in_register = true; |
| 167 | 170 |
| 168 // Possibly allocate a local context. | 171 // Possibly allocate a local context. |
| 169 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 172 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 170 if (heap_slots > 0) { | 173 if (heap_slots > 0) { |
| 171 Comment cmnt(masm_, "[ Allocate local context"); | 174 Comment cmnt(masm_, "[ Allocate local context"); |
| 172 // Argument to NewContext is the function, which is still in edi. | 175 // Argument to NewContext is the function, which is still in edi. |
| 173 __ push(edi); | 176 __ push(edi); |
| 174 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 177 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 175 FastNewContextStub stub(heap_slots); | 178 FastNewContextStub stub(heap_slots); |
| 176 __ CallStub(&stub); | 179 __ CallStub(&stub); |
| 177 } else { | 180 } else { |
| 178 __ CallRuntime(Runtime::kNewContext, 1); | 181 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
| 179 } | 182 } |
| 180 function_in_register = false; | 183 function_in_register = false; |
| 181 // Context is returned in both eax and esi. It replaces the context | 184 // Context is returned in both eax and esi. It replaces the context |
| 182 // passed to us. It's saved in the stack and kept live in esi. | 185 // passed to us. It's saved in the stack and kept live in esi. |
| 183 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); | 186 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
| 184 | 187 |
| 185 // Copy parameters into context if necessary. | 188 // Copy parameters into context if necessary. |
| 186 int num_parameters = scope()->num_parameters(); | 189 int num_parameters = info->scope()->num_parameters(); |
| 187 for (int i = 0; i < num_parameters; i++) { | 190 for (int i = 0; i < num_parameters; i++) { |
| 188 Slot* slot = scope()->parameter(i)->AsSlot(); | 191 Slot* slot = scope()->parameter(i)->AsSlot(); |
| 189 if (slot != NULL && slot->type() == Slot::CONTEXT) { | 192 if (slot != NULL && slot->type() == Slot::CONTEXT) { |
| 190 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 193 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 191 (num_parameters - 1 - i) * kPointerSize; | 194 (num_parameters - 1 - i) * kPointerSize; |
| 192 // Load parameter from stack. | 195 // Load parameter from stack. |
| 193 __ mov(eax, Operand(ebp, parameter_offset)); | 196 __ mov(eax, Operand(ebp, parameter_offset)); |
| 194 // Store it in the context. | 197 // Store it in the context. |
| 195 int context_offset = Context::SlotOffset(slot->index()); | 198 int context_offset = Context::SlotOffset(slot->index()); |
| 196 __ mov(Operand(esi, context_offset), eax); | 199 __ mov(Operand(esi, context_offset), eax); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 207 Variable* arguments = scope()->arguments(); | 210 Variable* arguments = scope()->arguments(); |
| 208 if (arguments != NULL) { | 211 if (arguments != NULL) { |
| 209 // Function uses arguments object. | 212 // Function uses arguments object. |
| 210 Comment cmnt(masm_, "[ Allocate arguments object"); | 213 Comment cmnt(masm_, "[ Allocate arguments object"); |
| 211 if (function_in_register) { | 214 if (function_in_register) { |
| 212 __ push(edi); | 215 __ push(edi); |
| 213 } else { | 216 } else { |
| 214 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 217 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 215 } | 218 } |
| 216 // Receiver is just before the parameters on the caller's stack. | 219 // Receiver is just before the parameters on the caller's stack. |
| 217 int offset = scope()->num_parameters() * kPointerSize; | 220 int num_parameters = info->scope()->num_parameters(); |
| 221 int offset = num_parameters * kPointerSize; |
| 218 __ lea(edx, | 222 __ lea(edx, |
| 219 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); | 223 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset)); |
| 220 __ push(edx); | 224 __ push(edx); |
| 221 __ SafePush(Immediate(Smi::FromInt(scope()->num_parameters()))); | 225 __ SafePush(Immediate(Smi::FromInt(num_parameters))); |
| 222 // Arguments to ArgumentsAccessStub: | 226 // Arguments to ArgumentsAccessStub and/or New...: |
| 223 // function, receiver address, parameter count. | 227 // function, receiver address, parameter count. |
| 224 // The stub will rewrite receiver and parameter count if the previous | 228 // The stub will rewrite receiver and parameter count if the previous |
| 225 // stack frame was an arguments adapter frame. | 229 // stack frame was an arguments adapter frame. |
| 226 ArgumentsAccessStub stub( | 230 ArgumentsAccessStub::Type type; |
| 227 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT | 231 if (is_strict_mode()) { |
| 228 : ArgumentsAccessStub::NEW_NON_STRICT); | 232 type = ArgumentsAccessStub::NEW_STRICT; |
| 233 } else if (function()->has_duplicate_parameters()) { |
| 234 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW; |
| 235 } else { |
| 236 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST; |
| 237 } |
| 238 ArgumentsAccessStub stub(type); |
| 229 __ CallStub(&stub); | 239 __ CallStub(&stub); |
| 230 | 240 |
| 231 Variable* arguments_shadow = scope()->arguments_shadow(); | |
| 232 if (arguments_shadow != NULL) { | |
| 233 __ mov(ecx, eax); // Duplicate result. | |
| 234 Move(arguments_shadow->AsSlot(), ecx, ebx, edx); | |
| 235 } | |
| 236 Move(arguments->AsSlot(), eax, ebx, edx); | 241 Move(arguments->AsSlot(), eax, ebx, edx); |
| 237 } | 242 } |
| 238 | 243 |
| 239 if (FLAG_trace) { | 244 if (FLAG_trace) { |
| 240 __ CallRuntime(Runtime::kTraceEnter, 0); | 245 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 241 } | 246 } |
| 242 | 247 |
| 243 // Visit the declarations and body unless there is an illegal | 248 // Visit the declarations and body unless there is an illegal |
| 244 // redeclaration. | 249 // redeclaration. |
| 245 if (scope()->HasIllegalRedeclaration()) { | 250 if (scope()->HasIllegalRedeclaration()) { |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 Label check_exit_codesize; | 340 Label check_exit_codesize; |
| 336 masm_->bind(&check_exit_codesize); | 341 masm_->bind(&check_exit_codesize); |
| 337 #endif | 342 #endif |
| 338 SetSourcePosition(function()->end_position() - 1); | 343 SetSourcePosition(function()->end_position() - 1); |
| 339 __ RecordJSReturn(); | 344 __ RecordJSReturn(); |
| 340 // Do not use the leave instruction here because it is too short to | 345 // Do not use the leave instruction here because it is too short to |
| 341 // patch with the code required by the debugger. | 346 // patch with the code required by the debugger. |
| 342 __ mov(esp, ebp); | 347 __ mov(esp, ebp); |
| 343 __ pop(ebp); | 348 __ pop(ebp); |
| 344 | 349 |
| 345 int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize; | 350 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize; |
| 346 __ Ret(arguments_bytes, ecx); | 351 __ Ret(arguments_bytes, ecx); |
| 347 #ifdef ENABLE_DEBUGGER_SUPPORT | 352 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 348 // Check that the size of the code used for returning is large enough | 353 // Check that the size of the code used for returning is large enough |
| 349 // for the debugger's requirements. | 354 // for the debugger's requirements. |
| 350 ASSERT(Assembler::kJSReturnSequenceLength <= | 355 ASSERT(Assembler::kJSReturnSequenceLength <= |
| 351 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 356 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 352 #endif | 357 #endif |
| 353 } | 358 } |
| 354 } | 359 } |
| 355 | 360 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 368 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); | 373 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); |
| 369 // Memory operands can be pushed directly. | 374 // Memory operands can be pushed directly. |
| 370 __ push(slot_operand); | 375 __ push(slot_operand); |
| 371 } | 376 } |
| 372 | 377 |
| 373 | 378 |
| 374 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { | 379 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { |
| 375 // For simplicity we always test the accumulator register. | 380 // For simplicity we always test the accumulator register. |
| 376 codegen()->Move(result_register(), slot); | 381 codegen()->Move(result_register(), slot); |
| 377 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 382 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 378 codegen()->DoTest(true_label_, false_label_, fall_through_); | 383 codegen()->DoTest(this); |
| 379 } | 384 } |
| 380 | 385 |
| 381 | 386 |
| 382 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { | 387 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { |
| 383 UNREACHABLE(); // Not used on IA32. | 388 UNREACHABLE(); // Not used on IA32. |
| 384 } | 389 } |
| 385 | 390 |
| 386 | 391 |
| 387 void FullCodeGenerator::AccumulatorValueContext::Plug( | 392 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 388 Heap::RootListIndex index) const { | 393 Heap::RootListIndex index) const { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 442 } | 447 } |
| 443 } else if (lit->IsSmi()) { | 448 } else if (lit->IsSmi()) { |
| 444 if (Smi::cast(*lit)->value() == 0) { | 449 if (Smi::cast(*lit)->value() == 0) { |
| 445 if (false_label_ != fall_through_) __ jmp(false_label_); | 450 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 446 } else { | 451 } else { |
| 447 if (true_label_ != fall_through_) __ jmp(true_label_); | 452 if (true_label_ != fall_through_) __ jmp(true_label_); |
| 448 } | 453 } |
| 449 } else { | 454 } else { |
| 450 // For simplicity we always test the accumulator register. | 455 // For simplicity we always test the accumulator register. |
| 451 __ mov(result_register(), lit); | 456 __ mov(result_register(), lit); |
| 452 codegen()->DoTest(true_label_, false_label_, fall_through_); | 457 codegen()->DoTest(this); |
| 453 } | 458 } |
| 454 } | 459 } |
| 455 | 460 |
| 456 | 461 |
| 457 void FullCodeGenerator::EffectContext::DropAndPlug(int count, | 462 void FullCodeGenerator::EffectContext::DropAndPlug(int count, |
| 458 Register reg) const { | 463 Register reg) const { |
| 459 ASSERT(count > 0); | 464 ASSERT(count > 0); |
| 460 __ Drop(count); | 465 __ Drop(count); |
| 461 } | 466 } |
| 462 | 467 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 478 } | 483 } |
| 479 | 484 |
| 480 | 485 |
| 481 void FullCodeGenerator::TestContext::DropAndPlug(int count, | 486 void FullCodeGenerator::TestContext::DropAndPlug(int count, |
| 482 Register reg) const { | 487 Register reg) const { |
| 483 ASSERT(count > 0); | 488 ASSERT(count > 0); |
| 484 // For simplicity we always test the accumulator register. | 489 // For simplicity we always test the accumulator register. |
| 485 __ Drop(count); | 490 __ Drop(count); |
| 486 __ Move(result_register(), reg); | 491 __ Move(result_register(), reg); |
| 487 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 492 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 488 codegen()->DoTest(true_label_, false_label_, fall_through_); | 493 codegen()->DoTest(this); |
| 489 } | 494 } |
| 490 | 495 |
| 491 | 496 |
| 492 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, | 497 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, |
| 493 Label* materialize_false) const { | 498 Label* materialize_false) const { |
| 494 ASSERT(materialize_true == materialize_false); | 499 ASSERT(materialize_true == materialize_false); |
| 495 __ bind(materialize_true); | 500 __ bind(materialize_true); |
| 496 } | 501 } |
| 497 | 502 |
| 498 | 503 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 true_label_, | 560 true_label_, |
| 556 false_label_); | 561 false_label_); |
| 557 if (flag) { | 562 if (flag) { |
| 558 if (true_label_ != fall_through_) __ jmp(true_label_); | 563 if (true_label_ != fall_through_) __ jmp(true_label_); |
| 559 } else { | 564 } else { |
| 560 if (false_label_ != fall_through_) __ jmp(false_label_); | 565 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 561 } | 566 } |
| 562 } | 567 } |
| 563 | 568 |
| 564 | 569 |
| 565 void FullCodeGenerator::DoTest(Label* if_true, | 570 void FullCodeGenerator::DoTest(Expression* condition, |
| 571 Label* if_true, |
| 566 Label* if_false, | 572 Label* if_false, |
| 567 Label* fall_through) { | 573 Label* fall_through) { |
| 568 ToBooleanStub stub; | 574 ToBooleanStub stub(result_register()); |
| 569 __ push(result_register()); | 575 __ push(result_register()); |
| 570 __ CallStub(&stub); | 576 __ CallStub(&stub); |
| 571 __ test(eax, Operand(eax)); | 577 __ test(result_register(), Operand(result_register())); |
| 572 // The stub returns nonzero for true. | 578 // The stub returns nonzero for true. |
| 573 Split(not_zero, if_true, if_false, fall_through); | 579 Split(not_zero, if_true, if_false, fall_through); |
| 574 } | 580 } |
| 575 | 581 |
| 576 | 582 |
| 577 void FullCodeGenerator::Split(Condition cc, | 583 void FullCodeGenerator::Split(Condition cc, |
| 578 Label* if_true, | 584 Label* if_true, |
| 579 Label* if_false, | 585 Label* if_false, |
| 580 Label* fall_through) { | 586 Label* fall_through) { |
| 581 if (if_false == fall_through) { | 587 if (if_false == fall_through) { |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 680 break; | 686 break; |
| 681 | 687 |
| 682 case Slot::CONTEXT: | 688 case Slot::CONTEXT: |
| 683 // We bypass the general EmitSlotSearch because we know more about | 689 // We bypass the general EmitSlotSearch because we know more about |
| 684 // this specific context. | 690 // this specific context. |
| 685 | 691 |
| 686 // The variable in the decl always resides in the current function | 692 // The variable in the decl always resides in the current function |
| 687 // context. | 693 // context. |
| 688 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 694 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 689 if (FLAG_debug_code) { | 695 if (FLAG_debug_code) { |
| 690 // Check that we're not inside a 'with'. | 696 // Check that we're not inside a with or catch context. |
| 691 __ mov(ebx, ContextOperand(esi, Context::FCONTEXT_INDEX)); | 697 __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset)); |
| 692 __ cmp(ebx, Operand(esi)); | 698 __ cmp(ebx, isolate()->factory()->with_context_map()); |
| 693 __ Check(equal, "Unexpected declaration in current context."); | 699 __ Check(not_equal, "Declaration in with context."); |
| 700 __ cmp(ebx, isolate()->factory()->catch_context_map()); |
| 701 __ Check(not_equal, "Declaration in catch context."); |
| 694 } | 702 } |
| 695 if (mode == Variable::CONST) { | 703 if (mode == Variable::CONST) { |
| 696 __ mov(ContextOperand(esi, slot->index()), | 704 __ mov(ContextOperand(esi, slot->index()), |
| 697 Immediate(isolate()->factory()->the_hole_value())); | 705 Immediate(isolate()->factory()->the_hole_value())); |
| 698 // No write barrier since the hole value is in old space. | 706 // No write barrier since the hole value is in old space, root and is |
| 707 // never evacuated from the page. |
| 699 } else if (function != NULL) { | 708 } else if (function != NULL) { |
| 700 VisitForAccumulatorValue(function); | 709 VisitForAccumulatorValue(function); |
| 701 __ mov(ContextOperand(esi, slot->index()), result_register()); | 710 __ mov(ContextOperand(esi, slot->index()), result_register()); |
| 702 int offset = Context::SlotOffset(slot->index()); | 711 int offset = Context::SlotOffset(slot->index()); |
| 703 // We know that we have written a function, which is not a smi. | 712 // We know that we have written a function, which is not a smi. |
| 704 __ RecordWriteContextSlot(esi, | 713 __ RecordWriteContextSlot(esi, |
| 705 offset, | 714 offset, |
| 706 result_register(), | 715 result_register(), |
| 707 ecx, | 716 ecx, |
| 708 kDontSaveFPRegs, | 717 kDontSaveFPRegs, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 751 VisitForAccumulatorValue(function); | 760 VisitForAccumulatorValue(function); |
| 752 __ pop(edx); | 761 __ pop(edx); |
| 753 | 762 |
| 754 ASSERT(prop->key()->AsLiteral() != NULL && | 763 ASSERT(prop->key()->AsLiteral() != NULL && |
| 755 prop->key()->AsLiteral()->handle()->IsSmi()); | 764 prop->key()->AsLiteral()->handle()->IsSmi()); |
| 756 __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle())); | 765 __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle())); |
| 757 | 766 |
| 758 Handle<Code> ic = is_strict_mode() | 767 Handle<Code> ic = is_strict_mode() |
| 759 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 768 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 760 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 769 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 761 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 770 __ call(ic); |
| 762 } | 771 } |
| 763 } | 772 } |
| 764 } | 773 } |
| 765 | 774 |
| 766 | 775 |
| 767 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 776 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 768 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 777 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 769 } | 778 } |
| 770 | 779 |
| 771 | 780 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 824 __ cmp(edx, Operand(eax)); | 833 __ cmp(edx, Operand(eax)); |
| 825 __ j(not_equal, &next_test); | 834 __ j(not_equal, &next_test); |
| 826 __ Drop(1); // Switch value is no longer needed. | 835 __ Drop(1); // Switch value is no longer needed. |
| 827 __ jmp(clause->body_target()); | 836 __ jmp(clause->body_target()); |
| 828 __ bind(&slow_case); | 837 __ bind(&slow_case); |
| 829 } | 838 } |
| 830 | 839 |
| 831 // Record position before stub call for type feedback. | 840 // Record position before stub call for type feedback. |
| 832 SetSourcePosition(clause->position()); | 841 SetSourcePosition(clause->position()); |
| 833 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); | 842 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); |
| 834 EmitCallIC(ic, &patch_site, clause->CompareId()); | 843 __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId()); |
| 844 patch_site.EmitPatchInfo(); |
| 835 __ test(eax, Operand(eax)); | 845 __ test(eax, Operand(eax)); |
| 836 __ j(not_equal, &next_test); | 846 __ j(not_equal, &next_test); |
| 837 __ Drop(1); // Switch value is no longer needed. | 847 __ Drop(1); // Switch value is no longer needed. |
| 838 __ jmp(clause->body_target()); | 848 __ jmp(clause->body_target()); |
| 839 } | 849 } |
| 840 | 850 |
| 841 // Discard the test value and jump to the default if present, otherwise to | 851 // Discard the test value and jump to the default if present, otherwise to |
| 842 // the end of the statement. | 852 // the end of the statement. |
| 843 __ bind(&next_test); | 853 __ bind(&next_test); |
| 844 __ Drop(1); // Switch value is no longer needed. | 854 __ Drop(1); // Switch value is no longer needed. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 874 // ignore null and undefined in contrast to the specification; see | 884 // ignore null and undefined in contrast to the specification; see |
| 875 // ECMA-262 section 12.6.4. | 885 // ECMA-262 section 12.6.4. |
| 876 VisitForAccumulatorValue(stmt->enumerable()); | 886 VisitForAccumulatorValue(stmt->enumerable()); |
| 877 __ cmp(eax, isolate()->factory()->undefined_value()); | 887 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 878 __ j(equal, &exit); | 888 __ j(equal, &exit); |
| 879 __ cmp(eax, isolate()->factory()->null_value()); | 889 __ cmp(eax, isolate()->factory()->null_value()); |
| 880 __ j(equal, &exit); | 890 __ j(equal, &exit); |
| 881 | 891 |
| 882 // Convert the object to a JS object. | 892 // Convert the object to a JS object. |
| 883 Label convert, done_convert; | 893 Label convert, done_convert; |
| 884 __ test(eax, Immediate(kSmiTagMask)); | 894 __ JumpIfSmi(eax, &convert, Label::kNear); |
| 885 __ j(zero, &convert, Label::kNear); | 895 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); |
| 886 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | |
| 887 __ j(above_equal, &done_convert, Label::kNear); | 896 __ j(above_equal, &done_convert, Label::kNear); |
| 888 __ bind(&convert); | 897 __ bind(&convert); |
| 889 __ push(eax); | 898 __ push(eax); |
| 890 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 899 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 891 __ bind(&done_convert); | 900 __ bind(&done_convert); |
| 892 __ push(eax); | 901 __ push(eax); |
| 893 | 902 |
| 894 // Check cache validity in generated code. This is a fast case for | 903 // Check cache validity in generated code. This is a fast case for |
| 895 // the JSObject::IsSimpleEnum cache validity checks. If we cannot | 904 // the JSObject::IsSimpleEnum cache validity checks. If we cannot |
| 896 // guarantee cache validity, call the runtime system to check cache | 905 // guarantee cache validity, call the runtime system to check cache |
| (...skipping 12 matching lines...) Expand all Loading... |
| 909 // check for an enum cache. Leave the map in ebx for the subsequent | 918 // check for an enum cache. Leave the map in ebx for the subsequent |
| 910 // prototype load. | 919 // prototype load. |
| 911 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); | 920 __ mov(ebx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 912 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOrBitField3Offset)); | 921 __ mov(edx, FieldOperand(ebx, Map::kInstanceDescriptorsOrBitField3Offset)); |
| 913 __ JumpIfSmi(edx, &call_runtime); | 922 __ JumpIfSmi(edx, &call_runtime); |
| 914 | 923 |
| 915 // Check that there is an enum cache in the non-empty instance | 924 // Check that there is an enum cache in the non-empty instance |
| 916 // descriptors (edx). This is the case if the next enumeration | 925 // descriptors (edx). This is the case if the next enumeration |
| 917 // index field does not contain a smi. | 926 // index field does not contain a smi. |
| 918 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); | 927 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumerationIndexOffset)); |
| 919 __ test(edx, Immediate(kSmiTagMask)); | 928 __ JumpIfSmi(edx, &call_runtime); |
| 920 __ j(zero, &call_runtime); | |
| 921 | 929 |
| 922 // For all objects but the receiver, check that the cache is empty. | 930 // For all objects but the receiver, check that the cache is empty. |
| 923 Label check_prototype; | 931 Label check_prototype; |
| 924 __ cmp(ecx, Operand(eax)); | 932 __ cmp(ecx, Operand(eax)); |
| 925 __ j(equal, &check_prototype, Label::kNear); | 933 __ j(equal, &check_prototype, Label::kNear); |
| 926 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 934 __ mov(edx, FieldOperand(edx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 927 __ cmp(edx, isolate()->factory()->empty_fixed_array()); | 935 __ cmp(edx, isolate()->factory()->empty_fixed_array()); |
| 928 __ j(not_equal, &call_runtime); | 936 __ j(not_equal, &call_runtime); |
| 929 | 937 |
| 930 // Load the prototype from the map and loop if non-null. | 938 // Load the prototype from the map and loop if non-null. |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1079 Scope* s = scope(); | 1087 Scope* s = scope(); |
| 1080 while (s != NULL) { | 1088 while (s != NULL) { |
| 1081 if (s->num_heap_slots() > 0) { | 1089 if (s->num_heap_slots() > 0) { |
| 1082 if (s->calls_eval()) { | 1090 if (s->calls_eval()) { |
| 1083 // Check that extension is NULL. | 1091 // Check that extension is NULL. |
| 1084 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), | 1092 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), |
| 1085 Immediate(0)); | 1093 Immediate(0)); |
| 1086 __ j(not_equal, slow); | 1094 __ j(not_equal, slow); |
| 1087 } | 1095 } |
| 1088 // Load next context in chain. | 1096 // Load next context in chain. |
| 1089 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX)); | 1097 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); |
| 1090 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); | |
| 1091 // Walk the rest of the chain without clobbering esi. | 1098 // Walk the rest of the chain without clobbering esi. |
| 1092 context = temp; | 1099 context = temp; |
| 1093 } | 1100 } |
| 1094 // If no outer scope calls eval, we do not need to check more | 1101 // If no outer scope calls eval, we do not need to check more |
| 1095 // context extensions. If we have reached an eval scope, we check | 1102 // context extensions. If we have reached an eval scope, we check |
| 1096 // all extensions from this point. | 1103 // all extensions from this point. |
| 1097 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; | 1104 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; |
| 1098 s = s->outer_scope(); | 1105 s = s->outer_scope(); |
| 1099 } | 1106 } |
| 1100 | 1107 |
| 1101 if (s != NULL && s->is_eval_scope()) { | 1108 if (s != NULL && s->is_eval_scope()) { |
| 1102 // Loop up the context chain. There is no frame effect so it is | 1109 // Loop up the context chain. There is no frame effect so it is |
| 1103 // safe to use raw labels here. | 1110 // safe to use raw labels here. |
| 1104 Label next, fast; | 1111 Label next, fast; |
| 1105 if (!context.is(temp)) { | 1112 if (!context.is(temp)) { |
| 1106 __ mov(temp, context); | 1113 __ mov(temp, context); |
| 1107 } | 1114 } |
| 1108 __ bind(&next); | 1115 __ bind(&next); |
| 1109 // Terminate at global context. | 1116 // Terminate at global context. |
| 1110 __ cmp(FieldOperand(temp, HeapObject::kMapOffset), | 1117 __ cmp(FieldOperand(temp, HeapObject::kMapOffset), |
| 1111 Immediate(isolate()->factory()->global_context_map())); | 1118 Immediate(isolate()->factory()->global_context_map())); |
| 1112 __ j(equal, &fast, Label::kNear); | 1119 __ j(equal, &fast, Label::kNear); |
| 1113 // Check that extension is NULL. | 1120 // Check that extension is NULL. |
| 1114 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); | 1121 __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); |
| 1115 __ j(not_equal, slow); | 1122 __ j(not_equal, slow); |
| 1116 // Load next context in chain. | 1123 // Load next context in chain. |
| 1117 __ mov(temp, ContextOperand(temp, Context::CLOSURE_INDEX)); | 1124 __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX)); |
| 1118 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); | |
| 1119 __ jmp(&next); | 1125 __ jmp(&next); |
| 1120 __ bind(&fast); | 1126 __ bind(&fast); |
| 1121 } | 1127 } |
| 1122 | 1128 |
| 1123 // All extension objects were empty and it is safe to use a global | 1129 // All extension objects were empty and it is safe to use a global |
| 1124 // load IC call. | 1130 // load IC call. |
| 1125 __ mov(eax, GlobalObjectOperand()); | 1131 __ mov(eax, GlobalObjectOperand()); |
| 1126 __ mov(ecx, slot->var()->name()); | 1132 __ mov(ecx, slot->var()->name()); |
| 1127 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1133 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 1128 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) | 1134 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
| 1129 ? RelocInfo::CODE_TARGET | 1135 ? RelocInfo::CODE_TARGET |
| 1130 : RelocInfo::CODE_TARGET_CONTEXT; | 1136 : RelocInfo::CODE_TARGET_CONTEXT; |
| 1131 EmitCallIC(ic, mode, AstNode::kNoNumber); | 1137 __ call(ic, mode); |
| 1132 } | 1138 } |
| 1133 | 1139 |
| 1134 | 1140 |
| 1135 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( | 1141 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( |
| 1136 Slot* slot, | 1142 Slot* slot, |
| 1137 Label* slow) { | 1143 Label* slow) { |
| 1138 ASSERT(slot->type() == Slot::CONTEXT); | 1144 ASSERT(slot->type() == Slot::CONTEXT); |
| 1139 Register context = esi; | 1145 Register context = esi; |
| 1140 Register temp = ebx; | 1146 Register temp = ebx; |
| 1141 | 1147 |
| 1142 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { | 1148 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { |
| 1143 if (s->num_heap_slots() > 0) { | 1149 if (s->num_heap_slots() > 0) { |
| 1144 if (s->calls_eval()) { | 1150 if (s->calls_eval()) { |
| 1145 // Check that extension is NULL. | 1151 // Check that extension is NULL. |
| 1146 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), | 1152 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), |
| 1147 Immediate(0)); | 1153 Immediate(0)); |
| 1148 __ j(not_equal, slow); | 1154 __ j(not_equal, slow); |
| 1149 } | 1155 } |
| 1150 __ mov(temp, ContextOperand(context, Context::CLOSURE_INDEX)); | 1156 __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); |
| 1151 __ mov(temp, FieldOperand(temp, JSFunction::kContextOffset)); | |
| 1152 // Walk the rest of the chain without clobbering esi. | 1157 // Walk the rest of the chain without clobbering esi. |
| 1153 context = temp; | 1158 context = temp; |
| 1154 } | 1159 } |
| 1155 } | 1160 } |
| 1156 // Check that last extension is NULL. | 1161 // Check that last extension is NULL. |
| 1157 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); | 1162 __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); |
| 1158 __ j(not_equal, slow); | 1163 __ j(not_equal, slow); |
| 1159 | 1164 |
| 1160 // This function is used only for loads, not stores, so it's safe to | 1165 // This function is used only for loads, not stores, so it's safe to |
| 1161 // return an esi-based operand (the write barrier cannot be allowed to | 1166 // return an esi-based operand (the write barrier cannot be allowed to |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1202 key_literal->handle()->IsSmi()) { | 1207 key_literal->handle()->IsSmi()) { |
| 1203 // Load arguments object if there are no eval-introduced | 1208 // Load arguments object if there are no eval-introduced |
| 1204 // variables. Then load the argument from the arguments | 1209 // variables. Then load the argument from the arguments |
| 1205 // object using keyed load. | 1210 // object using keyed load. |
| 1206 __ mov(edx, | 1211 __ mov(edx, |
| 1207 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), | 1212 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), |
| 1208 slow)); | 1213 slow)); |
| 1209 __ SafeSet(eax, Immediate(key_literal->handle())); | 1214 __ SafeSet(eax, Immediate(key_literal->handle())); |
| 1210 Handle<Code> ic = | 1215 Handle<Code> ic = |
| 1211 isolate()->builtins()->KeyedLoadIC_Initialize(); | 1216 isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 1212 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); | 1217 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); |
| 1213 __ jmp(done); | 1218 __ jmp(done); |
| 1214 } | 1219 } |
| 1215 } | 1220 } |
| 1216 } | 1221 } |
| 1217 } | 1222 } |
| 1218 } | 1223 } |
| 1219 | 1224 |
| 1220 | 1225 |
| 1221 void FullCodeGenerator::EmitVariableLoad(Variable* var) { | 1226 void FullCodeGenerator::EmitVariableLoad(Variable* var) { |
| 1222 // Four cases: non-this global variables, lookup slots, all other | 1227 // Three cases: non-this global variables, lookup slots, and all other |
| 1223 // types of slots, and parameters that rewrite to explicit property | 1228 // types of slots. |
| 1224 // accesses on the arguments object. | |
| 1225 Slot* slot = var->AsSlot(); | 1229 Slot* slot = var->AsSlot(); |
| 1226 Property* property = var->AsProperty(); | 1230 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); |
| 1227 | 1231 |
| 1228 if (var->is_global() && !var->is_this()) { | 1232 if (slot == NULL) { |
| 1229 Comment cmnt(masm_, "Global variable"); | 1233 Comment cmnt(masm_, "Global variable"); |
| 1230 // Use inline caching. Variable name is passed in ecx and the global | 1234 // Use inline caching. Variable name is passed in ecx and the global |
| 1231 // object on the stack. | 1235 // object on the stack. |
| 1232 __ mov(eax, GlobalObjectOperand()); | 1236 __ mov(eax, GlobalObjectOperand()); |
| 1233 __ mov(ecx, var->name()); | 1237 __ mov(ecx, var->name()); |
| 1234 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1238 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 1235 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); | 1239 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1236 context()->Plug(eax); | 1240 context()->Plug(eax); |
| 1237 | 1241 |
| 1238 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1242 } else if (slot->type() == Slot::LOOKUP) { |
| 1239 Label done, slow; | 1243 Label done, slow; |
| 1240 | 1244 |
| 1241 // Generate code for loading from variables potentially shadowed | 1245 // Generate code for loading from variables potentially shadowed |
| 1242 // by eval-introduced variables. | 1246 // by eval-introduced variables. |
| 1243 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 1247 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1244 | 1248 |
| 1245 __ bind(&slow); | 1249 __ bind(&slow); |
| 1246 Comment cmnt(masm_, "Lookup slot"); | 1250 Comment cmnt(masm_, "Lookup slot"); |
| 1247 __ push(esi); // Context. | 1251 __ push(esi); // Context. |
| 1248 __ push(Immediate(var->name())); | 1252 __ push(Immediate(var->name())); |
| 1249 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1253 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1250 __ bind(&done); | 1254 __ bind(&done); |
| 1251 | 1255 |
| 1252 context()->Plug(eax); | 1256 context()->Plug(eax); |
| 1253 | 1257 |
| 1254 } else if (slot != NULL) { | 1258 } else { |
| 1255 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1259 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 1256 ? "Context slot" | 1260 ? "Context slot" |
| 1257 : "Stack slot"); | 1261 : "Stack slot"); |
| 1258 if (var->mode() == Variable::CONST) { | 1262 if (var->mode() == Variable::CONST) { |
| 1259 // Constants may be the hole value if they have not been initialized. | 1263 // Constants may be the hole value if they have not been initialized. |
| 1260 // Unhole them. | 1264 // Unhole them. |
| 1261 Label done; | 1265 Label done; |
| 1262 MemOperand slot_operand = EmitSlotSearch(slot, eax); | 1266 MemOperand slot_operand = EmitSlotSearch(slot, eax); |
| 1263 __ mov(eax, slot_operand); | 1267 __ mov(eax, slot_operand); |
| 1264 __ cmp(eax, isolate()->factory()->the_hole_value()); | 1268 __ cmp(eax, isolate()->factory()->the_hole_value()); |
| 1265 __ j(not_equal, &done, Label::kNear); | 1269 __ j(not_equal, &done, Label::kNear); |
| 1266 __ mov(eax, isolate()->factory()->undefined_value()); | 1270 __ mov(eax, isolate()->factory()->undefined_value()); |
| 1267 __ bind(&done); | 1271 __ bind(&done); |
| 1268 context()->Plug(eax); | 1272 context()->Plug(eax); |
| 1269 } else { | 1273 } else { |
| 1270 context()->Plug(slot); | 1274 context()->Plug(slot); |
| 1271 } | 1275 } |
| 1272 | |
| 1273 } else { | |
| 1274 Comment cmnt(masm_, "Rewritten parameter"); | |
| 1275 ASSERT_NOT_NULL(property); | |
| 1276 // Rewritten parameter accesses are of the form "slot[literal]". | |
| 1277 | |
| 1278 // Assert that the object is in a slot. | |
| 1279 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); | |
| 1280 ASSERT_NOT_NULL(object_var); | |
| 1281 Slot* object_slot = object_var->AsSlot(); | |
| 1282 ASSERT_NOT_NULL(object_slot); | |
| 1283 | |
| 1284 // Load the object. | |
| 1285 MemOperand object_loc = EmitSlotSearch(object_slot, eax); | |
| 1286 __ mov(edx, object_loc); | |
| 1287 | |
| 1288 // Assert that the key is a smi. | |
| 1289 Literal* key_literal = property->key()->AsLiteral(); | |
| 1290 ASSERT_NOT_NULL(key_literal); | |
| 1291 ASSERT(key_literal->handle()->IsSmi()); | |
| 1292 | |
| 1293 // Load the key. | |
| 1294 __ SafeSet(eax, Immediate(key_literal->handle())); | |
| 1295 | |
| 1296 // Do a keyed property load. | |
| 1297 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | |
| 1298 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); | |
| 1299 | |
| 1300 // Drop key and object left on the stack by IC. | |
| 1301 context()->Plug(eax); | |
| 1302 } | 1276 } |
| 1303 } | 1277 } |
| 1304 | 1278 |
| 1305 | 1279 |
| 1306 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1280 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 1307 Comment cmnt(masm_, "[ RegExpLiteral"); | 1281 Comment cmnt(masm_, "[ RegExpLiteral"); |
| 1308 Label materialized; | 1282 Label materialized; |
| 1309 // Registers will be used as follows: | 1283 // Registers will be used as follows: |
| 1310 // edi = JS function. | 1284 // edi = JS function. |
| 1311 // ecx = literals array. | 1285 // ecx = literals array. |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1401 // Fall through. | 1375 // Fall through. |
| 1402 case ObjectLiteral::Property::COMPUTED: | 1376 case ObjectLiteral::Property::COMPUTED: |
| 1403 if (key->handle()->IsSymbol()) { | 1377 if (key->handle()->IsSymbol()) { |
| 1404 if (property->emit_store()) { | 1378 if (property->emit_store()) { |
| 1405 VisitForAccumulatorValue(value); | 1379 VisitForAccumulatorValue(value); |
| 1406 __ mov(ecx, Immediate(key->handle())); | 1380 __ mov(ecx, Immediate(key->handle())); |
| 1407 __ mov(edx, Operand(esp, 0)); | 1381 __ mov(edx, Operand(esp, 0)); |
| 1408 Handle<Code> ic = is_strict_mode() | 1382 Handle<Code> ic = is_strict_mode() |
| 1409 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1383 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 1410 : isolate()->builtins()->StoreIC_Initialize(); | 1384 : isolate()->builtins()->StoreIC_Initialize(); |
| 1411 EmitCallIC(ic, RelocInfo::CODE_TARGET, key->id()); | 1385 __ call(ic, RelocInfo::CODE_TARGET, key->id()); |
| 1412 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1386 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1413 } else { | 1387 } else { |
| 1414 VisitForEffect(value); | 1388 VisitForEffect(value); |
| 1415 } | 1389 } |
| 1416 break; | 1390 break; |
| 1417 } | 1391 } |
| 1418 // Fall through. | 1392 // Fall through. |
| 1419 case ObjectLiteral::Property::PROTOTYPE: | 1393 case ObjectLiteral::Property::PROTOTYPE: |
| 1420 __ push(Operand(esp, 0)); // Duplicate receiver. | 1394 __ push(Operand(esp, 0)); // Duplicate receiver. |
| 1421 VisitForStackValue(key); | 1395 VisitForStackValue(key); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1524 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1498 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
| 1525 Comment cmnt(masm_, "[ Assignment"); | 1499 Comment cmnt(masm_, "[ Assignment"); |
| 1526 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 1500 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 1527 // on the left-hand side. | 1501 // on the left-hand side. |
| 1528 if (!expr->target()->IsValidLeftHandSide()) { | 1502 if (!expr->target()->IsValidLeftHandSide()) { |
| 1529 VisitForEffect(expr->target()); | 1503 VisitForEffect(expr->target()); |
| 1530 return; | 1504 return; |
| 1531 } | 1505 } |
| 1532 | 1506 |
| 1533 // Left-hand side can only be a property, a global or a (parameter or local) | 1507 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1534 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1508 // slot. |
| 1535 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1509 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1536 LhsKind assign_type = VARIABLE; | 1510 LhsKind assign_type = VARIABLE; |
| 1537 Property* property = expr->target()->AsProperty(); | 1511 Property* property = expr->target()->AsProperty(); |
| 1538 if (property != NULL) { | 1512 if (property != NULL) { |
| 1539 assign_type = (property->key()->IsPropertyName()) | 1513 assign_type = (property->key()->IsPropertyName()) |
| 1540 ? NAMED_PROPERTY | 1514 ? NAMED_PROPERTY |
| 1541 : KEYED_PROPERTY; | 1515 : KEYED_PROPERTY; |
| 1542 } | 1516 } |
| 1543 | 1517 |
| 1544 // Evaluate LHS expression. | 1518 // Evaluate LHS expression. |
| 1545 switch (assign_type) { | 1519 switch (assign_type) { |
| 1546 case VARIABLE: | 1520 case VARIABLE: |
| 1547 // Nothing to do here. | 1521 // Nothing to do here. |
| 1548 break; | 1522 break; |
| 1549 case NAMED_PROPERTY: | 1523 case NAMED_PROPERTY: |
| 1550 if (expr->is_compound()) { | 1524 if (expr->is_compound()) { |
| 1551 // We need the receiver both on the stack and in the accumulator. | 1525 // We need the receiver both on the stack and in the accumulator. |
| 1552 VisitForAccumulatorValue(property->obj()); | 1526 VisitForAccumulatorValue(property->obj()); |
| 1553 __ push(result_register()); | 1527 __ push(result_register()); |
| 1554 } else { | 1528 } else { |
| 1555 VisitForStackValue(property->obj()); | 1529 VisitForStackValue(property->obj()); |
| 1556 } | 1530 } |
| 1557 break; | 1531 break; |
| 1558 case KEYED_PROPERTY: { | 1532 case KEYED_PROPERTY: { |
| 1559 if (expr->is_compound()) { | 1533 if (expr->is_compound()) { |
| 1560 if (property->is_arguments_access()) { | 1534 VisitForStackValue(property->obj()); |
| 1561 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1535 VisitForAccumulatorValue(property->key()); |
| 1562 MemOperand slot_operand = | |
| 1563 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); | |
| 1564 __ push(slot_operand); | |
| 1565 __ SafeSet(eax, Immediate(property->key()->AsLiteral()->handle())); | |
| 1566 } else { | |
| 1567 VisitForStackValue(property->obj()); | |
| 1568 VisitForAccumulatorValue(property->key()); | |
| 1569 } | |
| 1570 __ mov(edx, Operand(esp, 0)); | 1536 __ mov(edx, Operand(esp, 0)); |
| 1571 __ push(eax); | 1537 __ push(eax); |
| 1572 } else { | 1538 } else { |
| 1573 if (property->is_arguments_access()) { | 1539 VisitForStackValue(property->obj()); |
| 1574 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1540 VisitForStackValue(property->key()); |
| 1575 MemOperand slot_operand = | |
| 1576 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); | |
| 1577 __ push(slot_operand); | |
| 1578 __ SafePush(Immediate(property->key()->AsLiteral()->handle())); | |
| 1579 } else { | |
| 1580 VisitForStackValue(property->obj()); | |
| 1581 VisitForStackValue(property->key()); | |
| 1582 } | |
| 1583 } | 1541 } |
| 1584 break; | 1542 break; |
| 1585 } | 1543 } |
| 1586 } | 1544 } |
| 1587 | 1545 |
| 1588 // For compound assignments we need another deoptimization point after the | 1546 // For compound assignments we need another deoptimization point after the |
| 1589 // variable/property load. | 1547 // variable/property load. |
| 1590 if (expr->is_compound()) { | 1548 if (expr->is_compound()) { |
| 1591 { AccumulatorValueContext context(this); | 1549 { AccumulatorValueContext context(this); |
| 1592 switch (assign_type) { | 1550 switch (assign_type) { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1650 } | 1608 } |
| 1651 } | 1609 } |
| 1652 | 1610 |
| 1653 | 1611 |
| 1654 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { | 1612 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
| 1655 SetSourcePosition(prop->position()); | 1613 SetSourcePosition(prop->position()); |
| 1656 Literal* key = prop->key()->AsLiteral(); | 1614 Literal* key = prop->key()->AsLiteral(); |
| 1657 ASSERT(!key->handle()->IsSmi()); | 1615 ASSERT(!key->handle()->IsSmi()); |
| 1658 __ mov(ecx, Immediate(key->handle())); | 1616 __ mov(ecx, Immediate(key->handle())); |
| 1659 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1617 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 1660 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | 1618 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); |
| 1661 } | 1619 } |
| 1662 | 1620 |
| 1663 | 1621 |
| 1664 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 1622 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 1665 SetSourcePosition(prop->position()); | 1623 SetSourcePosition(prop->position()); |
| 1666 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 1624 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 1667 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | 1625 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); |
| 1668 } | 1626 } |
| 1669 | 1627 |
| 1670 | 1628 |
| 1671 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, | 1629 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, |
| 1672 Token::Value op, | 1630 Token::Value op, |
| 1673 OverwriteMode mode, | 1631 OverwriteMode mode, |
| 1674 Expression* left, | 1632 Expression* left, |
| 1675 Expression* right) { | 1633 Expression* right) { |
| 1676 // Do combined smi check of the operands. Left operand is on the | 1634 // Do combined smi check of the operands. Left operand is on the |
| 1677 // stack. Right operand is in eax. | 1635 // stack. Right operand is in eax. |
| 1678 Label smi_case, done, stub_call; | 1636 Label smi_case, done, stub_call; |
| 1679 __ pop(edx); | 1637 __ pop(edx); |
| 1680 __ mov(ecx, eax); | 1638 __ mov(ecx, eax); |
| 1681 __ or_(eax, Operand(edx)); | 1639 __ or_(eax, Operand(edx)); |
| 1682 JumpPatchSite patch_site(masm_); | 1640 JumpPatchSite patch_site(masm_); |
| 1683 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear); | 1641 patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear); |
| 1684 | 1642 |
| 1685 __ bind(&stub_call); | 1643 __ bind(&stub_call); |
| 1686 __ mov(eax, ecx); | 1644 __ mov(eax, ecx); |
| 1687 BinaryOpStub stub(op, mode); | 1645 BinaryOpStub stub(op, mode); |
| 1688 EmitCallIC(stub.GetCode(), &patch_site, expr->id()); | 1646 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| 1647 patch_site.EmitPatchInfo(); |
| 1689 __ jmp(&done, Label::kNear); | 1648 __ jmp(&done, Label::kNear); |
| 1690 | 1649 |
| 1691 // Smi case. | 1650 // Smi case. |
| 1692 __ bind(&smi_case); | 1651 __ bind(&smi_case); |
| 1693 __ mov(eax, edx); // Copy left operand in case of a stub call. | 1652 __ mov(eax, edx); // Copy left operand in case of a stub call. |
| 1694 | 1653 |
| 1695 switch (op) { | 1654 switch (op) { |
| 1696 case Token::SAR: | 1655 case Token::SAR: |
| 1697 __ SmiUntag(eax); | 1656 __ SmiUntag(eax); |
| 1698 __ SmiUntag(ecx); | 1657 __ SmiUntag(ecx); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1761 __ bind(&done); | 1720 __ bind(&done); |
| 1762 context()->Plug(eax); | 1721 context()->Plug(eax); |
| 1763 } | 1722 } |
| 1764 | 1723 |
| 1765 | 1724 |
| 1766 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, | 1725 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, |
| 1767 Token::Value op, | 1726 Token::Value op, |
| 1768 OverwriteMode mode) { | 1727 OverwriteMode mode) { |
| 1769 __ pop(edx); | 1728 __ pop(edx); |
| 1770 BinaryOpStub stub(op, mode); | 1729 BinaryOpStub stub(op, mode); |
| 1771 // NULL signals no inlined smi code. | 1730 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
| 1772 EmitCallIC(stub.GetCode(), NULL, expr->id()); | 1731 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| 1732 patch_site.EmitPatchInfo(); |
| 1773 context()->Plug(eax); | 1733 context()->Plug(eax); |
| 1774 } | 1734 } |
| 1775 | 1735 |
| 1776 | 1736 |
| 1777 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 1737 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
| 1778 // Invalid left-hand sides are rewritten to have a 'throw | 1738 // Invalid left-hand sides are rewritten to have a 'throw |
| 1779 // ReferenceError' on the left-hand side. | 1739 // ReferenceError' on the left-hand side. |
| 1780 if (!expr->IsValidLeftHandSide()) { | 1740 if (!expr->IsValidLeftHandSide()) { |
| 1781 VisitForEffect(expr); | 1741 VisitForEffect(expr); |
| 1782 return; | 1742 return; |
| 1783 } | 1743 } |
| 1784 | 1744 |
| 1785 // Left-hand side can only be a property, a global or a (parameter or local) | 1745 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1786 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1746 // slot. |
| 1787 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1747 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1788 LhsKind assign_type = VARIABLE; | 1748 LhsKind assign_type = VARIABLE; |
| 1789 Property* prop = expr->AsProperty(); | 1749 Property* prop = expr->AsProperty(); |
| 1790 if (prop != NULL) { | 1750 if (prop != NULL) { |
| 1791 assign_type = (prop->key()->IsPropertyName()) | 1751 assign_type = (prop->key()->IsPropertyName()) |
| 1792 ? NAMED_PROPERTY | 1752 ? NAMED_PROPERTY |
| 1793 : KEYED_PROPERTY; | 1753 : KEYED_PROPERTY; |
| 1794 } | 1754 } |
| 1795 | 1755 |
| 1796 switch (assign_type) { | 1756 switch (assign_type) { |
| 1797 case VARIABLE: { | 1757 case VARIABLE: { |
| 1798 Variable* var = expr->AsVariableProxy()->var(); | 1758 Variable* var = expr->AsVariableProxy()->var(); |
| 1799 EffectContext context(this); | 1759 EffectContext context(this); |
| 1800 EmitVariableAssignment(var, Token::ASSIGN); | 1760 EmitVariableAssignment(var, Token::ASSIGN); |
| 1801 break; | 1761 break; |
| 1802 } | 1762 } |
| 1803 case NAMED_PROPERTY: { | 1763 case NAMED_PROPERTY: { |
| 1804 __ push(eax); // Preserve value. | 1764 __ push(eax); // Preserve value. |
| 1805 VisitForAccumulatorValue(prop->obj()); | 1765 VisitForAccumulatorValue(prop->obj()); |
| 1806 __ mov(edx, eax); | 1766 __ mov(edx, eax); |
| 1807 __ pop(eax); // Restore value. | 1767 __ pop(eax); // Restore value. |
| 1808 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 1768 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 1809 Handle<Code> ic = is_strict_mode() | 1769 Handle<Code> ic = is_strict_mode() |
| 1810 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1770 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 1811 : isolate()->builtins()->StoreIC_Initialize(); | 1771 : isolate()->builtins()->StoreIC_Initialize(); |
| 1812 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 1772 __ call(ic); |
| 1813 break; | 1773 break; |
| 1814 } | 1774 } |
| 1815 case KEYED_PROPERTY: { | 1775 case KEYED_PROPERTY: { |
| 1816 __ push(eax); // Preserve value. | 1776 __ push(eax); // Preserve value. |
| 1817 if (prop->is_synthetic()) { | 1777 if (prop->is_synthetic()) { |
| 1818 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 1778 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 1819 ASSERT(prop->key()->AsLiteral() != NULL); | 1779 ASSERT(prop->key()->AsLiteral() != NULL); |
| 1820 { AccumulatorValueContext for_object(this); | 1780 { AccumulatorValueContext for_object(this); |
| 1821 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | 1781 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); |
| 1822 } | 1782 } |
| 1823 __ mov(edx, eax); | 1783 __ mov(edx, eax); |
| 1824 __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle())); | 1784 __ SafeSet(ecx, Immediate(prop->key()->AsLiteral()->handle())); |
| 1825 } else { | 1785 } else { |
| 1826 VisitForStackValue(prop->obj()); | 1786 VisitForStackValue(prop->obj()); |
| 1827 VisitForAccumulatorValue(prop->key()); | 1787 VisitForAccumulatorValue(prop->key()); |
| 1828 __ mov(ecx, eax); | 1788 __ mov(ecx, eax); |
| 1829 __ pop(edx); | 1789 __ pop(edx); |
| 1830 } | 1790 } |
| 1831 __ pop(eax); // Restore value. | 1791 __ pop(eax); // Restore value. |
| 1832 Handle<Code> ic = is_strict_mode() | 1792 Handle<Code> ic = is_strict_mode() |
| 1833 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 1793 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 1834 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 1794 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 1835 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 1795 __ call(ic); |
| 1836 break; | 1796 break; |
| 1837 } | 1797 } |
| 1838 } | 1798 } |
| 1839 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1799 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| 1840 context()->Plug(eax); | 1800 context()->Plug(eax); |
| 1841 } | 1801 } |
| 1842 | 1802 |
| 1843 | 1803 |
| 1844 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1804 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1845 Token::Value op) { | 1805 Token::Value op) { |
| 1846 // Left-hand sides that rewrite to explicit property accesses do not reach | |
| 1847 // here. | |
| 1848 ASSERT(var != NULL); | 1806 ASSERT(var != NULL); |
| 1849 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1807 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| 1850 | 1808 |
| 1851 if (var->is_global()) { | 1809 if (var->is_global()) { |
| 1852 ASSERT(!var->is_this()); | 1810 ASSERT(!var->is_this()); |
| 1853 // Assignment to a global variable. Use inline caching for the | 1811 // Assignment to a global variable. Use inline caching for the |
| 1854 // assignment. Right-hand-side value is passed in eax, variable name in | 1812 // assignment. Right-hand-side value is passed in eax, variable name in |
| 1855 // ecx, and the global object on the stack. | 1813 // ecx, and the global object on the stack. |
| 1856 __ mov(ecx, var->name()); | 1814 __ mov(ecx, var->name()); |
| 1857 __ mov(edx, GlobalObjectOperand()); | 1815 __ mov(edx, GlobalObjectOperand()); |
| 1858 Handle<Code> ic = is_strict_mode() | 1816 Handle<Code> ic = is_strict_mode() |
| 1859 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1817 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 1860 : isolate()->builtins()->StoreIC_Initialize(); | 1818 : isolate()->builtins()->StoreIC_Initialize(); |
| 1861 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); | 1819 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1862 | 1820 |
| 1863 } else if (op == Token::INIT_CONST) { | 1821 } else if (op == Token::INIT_CONST) { |
| 1864 // Like var declarations, const declarations are hoisted to function | 1822 // Like var declarations, const declarations are hoisted to function |
| 1865 // scope. However, unlike var initializers, const initializers are able | 1823 // scope. However, unlike var initializers, const initializers are able |
| 1866 // to drill a hole to that function context, even from inside a 'with' | 1824 // to drill a hole to that function context, even from inside a 'with' |
| 1867 // context. We thus bypass the normal static scope lookup. | 1825 // context. We thus bypass the normal static scope lookup. |
| 1868 Slot* slot = var->AsSlot(); | 1826 Slot* slot = var->AsSlot(); |
| 1869 Label skip; | 1827 Label skip; |
| 1870 switch (slot->type()) { | 1828 switch (slot->type()) { |
| 1871 case Slot::PARAMETER: | 1829 case Slot::PARAMETER: |
| 1872 // No const parameters. | 1830 // No const parameters. |
| 1873 UNREACHABLE(); | 1831 UNREACHABLE(); |
| 1874 break; | 1832 break; |
| 1875 case Slot::LOCAL: | 1833 case Slot::LOCAL: |
| 1876 __ mov(edx, Operand(ebp, SlotOffset(slot))); | 1834 __ mov(edx, Operand(ebp, SlotOffset(slot))); |
| 1877 __ cmp(edx, isolate()->factory()->the_hole_value()); | 1835 __ cmp(edx, isolate()->factory()->the_hole_value()); |
| 1878 __ j(not_equal, &skip); | 1836 __ j(not_equal, &skip); |
| 1879 __ mov(Operand(ebp, SlotOffset(slot)), eax); | 1837 __ mov(Operand(ebp, SlotOffset(slot)), eax); |
| 1880 break; | 1838 break; |
| 1881 case Slot::CONTEXT: { | 1839 case Slot::CONTEXT: |
| 1882 __ mov(ecx, ContextOperand(esi, Context::FCONTEXT_INDEX)); | |
| 1883 __ mov(edx, ContextOperand(ecx, slot->index())); | |
| 1884 __ cmp(edx, isolate()->factory()->the_hole_value()); | |
| 1885 __ j(not_equal, &skip); | |
| 1886 __ mov(ContextOperand(ecx, slot->index()), eax); | |
| 1887 int offset = Context::SlotOffset(slot->index()); | |
| 1888 __ mov(edx, eax); // Preserve the stored value in eax. | |
| 1889 __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs); | |
| 1890 break; | |
| 1891 } | |
| 1892 case Slot::LOOKUP: | 1840 case Slot::LOOKUP: |
| 1893 __ push(eax); | 1841 __ push(eax); |
| 1894 __ push(esi); | 1842 __ push(esi); |
| 1895 __ push(Immediate(var->name())); | 1843 __ push(Immediate(var->name())); |
| 1896 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 1844 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 1897 break; | 1845 break; |
| 1898 } | 1846 } |
| 1899 __ bind(&skip); | 1847 __ bind(&skip); |
| 1900 | 1848 |
| 1901 } else if (var->mode() != Variable::CONST) { | 1849 } else if (var->mode() != Variable::CONST) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1955 SetSourcePosition(expr->position()); | 1903 SetSourcePosition(expr->position()); |
| 1956 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 1904 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 1957 if (expr->ends_initialization_block()) { | 1905 if (expr->ends_initialization_block()) { |
| 1958 __ mov(edx, Operand(esp, 0)); | 1906 __ mov(edx, Operand(esp, 0)); |
| 1959 } else { | 1907 } else { |
| 1960 __ pop(edx); | 1908 __ pop(edx); |
| 1961 } | 1909 } |
| 1962 Handle<Code> ic = is_strict_mode() | 1910 Handle<Code> ic = is_strict_mode() |
| 1963 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1911 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 1964 : isolate()->builtins()->StoreIC_Initialize(); | 1912 : isolate()->builtins()->StoreIC_Initialize(); |
| 1965 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 1913 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 1966 | 1914 |
| 1967 // If the assignment ends an initialization block, revert to fast case. | 1915 // If the assignment ends an initialization block, revert to fast case. |
| 1968 if (expr->ends_initialization_block()) { | 1916 if (expr->ends_initialization_block()) { |
| 1969 __ push(eax); // Result of assignment, saved even if not needed. | 1917 __ push(eax); // Result of assignment, saved even if not needed. |
| 1970 __ push(Operand(esp, kPointerSize)); // Receiver is under value. | 1918 __ push(Operand(esp, kPointerSize)); // Receiver is under value. |
| 1971 __ CallRuntime(Runtime::kToFastProperties, 1); | 1919 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1972 __ pop(eax); | 1920 __ pop(eax); |
| 1973 __ Drop(1); | 1921 __ Drop(1); |
| 1974 } | 1922 } |
| 1975 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 1923 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1995 if (expr->ends_initialization_block()) { | 1943 if (expr->ends_initialization_block()) { |
| 1996 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. | 1944 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later. |
| 1997 } else { | 1945 } else { |
| 1998 __ pop(edx); | 1946 __ pop(edx); |
| 1999 } | 1947 } |
| 2000 // Record source code position before IC call. | 1948 // Record source code position before IC call. |
| 2001 SetSourcePosition(expr->position()); | 1949 SetSourcePosition(expr->position()); |
| 2002 Handle<Code> ic = is_strict_mode() | 1950 Handle<Code> ic = is_strict_mode() |
| 2003 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 1951 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 2004 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 1952 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 2005 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 1953 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 2006 | 1954 |
| 2007 // If the assignment ends an initialization block, revert to fast case. | 1955 // If the assignment ends an initialization block, revert to fast case. |
| 2008 if (expr->ends_initialization_block()) { | 1956 if (expr->ends_initialization_block()) { |
| 2009 __ pop(edx); | 1957 __ pop(edx); |
| 2010 __ push(eax); // Result of assignment, saved even if not needed. | 1958 __ push(eax); // Result of assignment, saved even if not needed. |
| 2011 __ push(edx); | 1959 __ push(edx); |
| 2012 __ CallRuntime(Runtime::kToFastProperties, 1); | 1960 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 2013 __ pop(eax); | 1961 __ pop(eax); |
| 2014 } | 1962 } |
| 2015 | 1963 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2046 for (int i = 0; i < arg_count; i++) { | 1994 for (int i = 0; i < arg_count; i++) { |
| 2047 VisitForStackValue(args->at(i)); | 1995 VisitForStackValue(args->at(i)); |
| 2048 } | 1996 } |
| 2049 __ Set(ecx, Immediate(name)); | 1997 __ Set(ecx, Immediate(name)); |
| 2050 } | 1998 } |
| 2051 // Record source position of the IC call. | 1999 // Record source position of the IC call. |
| 2052 SetSourcePosition(expr->position()); | 2000 SetSourcePosition(expr->position()); |
| 2053 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2001 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2054 Handle<Code> ic = | 2002 Handle<Code> ic = |
| 2055 isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); | 2003 isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); |
| 2056 EmitCallIC(ic, mode, expr->id()); | 2004 __ call(ic, mode, expr->id()); |
| 2057 RecordJSReturnSite(expr); | 2005 RecordJSReturnSite(expr); |
| 2058 // Restore context register. | 2006 // Restore context register. |
| 2059 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2007 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2060 context()->Plug(eax); | 2008 context()->Plug(eax); |
| 2061 } | 2009 } |
| 2062 | 2010 |
| 2063 | 2011 |
| 2064 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 2012 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 2065 Expression* key) { | 2013 Expression* key) { |
| 2066 // Load the key. | 2014 // Load the key. |
| (...skipping 12 matching lines...) Expand all Loading... |
| 2079 for (int i = 0; i < arg_count; i++) { | 2027 for (int i = 0; i < arg_count; i++) { |
| 2080 VisitForStackValue(args->at(i)); | 2028 VisitForStackValue(args->at(i)); |
| 2081 } | 2029 } |
| 2082 } | 2030 } |
| 2083 // Record source position of the IC call. | 2031 // Record source position of the IC call. |
| 2084 SetSourcePosition(expr->position()); | 2032 SetSourcePosition(expr->position()); |
| 2085 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2033 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2086 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize( | 2034 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize( |
| 2087 arg_count, in_loop); | 2035 arg_count, in_loop); |
| 2088 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key. | 2036 __ mov(ecx, Operand(esp, (arg_count + 1) * kPointerSize)); // Key. |
| 2089 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 2037 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 2090 RecordJSReturnSite(expr); | 2038 RecordJSReturnSite(expr); |
| 2091 // Restore context register. | 2039 // Restore context register. |
| 2092 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2040 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 2093 context()->DropAndPlug(1, eax); // Drop the key still on the stack. | 2041 context()->DropAndPlug(1, eax); // Drop the key still on the stack. |
| 2094 } | 2042 } |
| 2095 | 2043 |
| 2096 | 2044 |
| 2097 void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { | 2045 void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { |
| 2098 // Code common for calls using the call stub. | 2046 // Code common for calls using the call stub. |
| 2099 ZoneList<Expression*>* args = expr->arguments(); | 2047 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2118 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, | 2066 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, |
| 2119 int arg_count) { | 2067 int arg_count) { |
| 2120 // Push copy of the first argument or undefined if it doesn't exist. | 2068 // Push copy of the first argument or undefined if it doesn't exist. |
| 2121 if (arg_count > 0) { | 2069 if (arg_count > 0) { |
| 2122 __ push(Operand(esp, arg_count * kPointerSize)); | 2070 __ push(Operand(esp, arg_count * kPointerSize)); |
| 2123 } else { | 2071 } else { |
| 2124 __ push(Immediate(isolate()->factory()->undefined_value())); | 2072 __ push(Immediate(isolate()->factory()->undefined_value())); |
| 2125 } | 2073 } |
| 2126 | 2074 |
| 2127 // Push the receiver of the enclosing function. | 2075 // Push the receiver of the enclosing function. |
| 2128 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize)); | 2076 __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize)); |
| 2129 | 2077 |
| 2130 // Push the strict mode flag. | 2078 // Push the strict mode flag. |
| 2131 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); | 2079 __ push(Immediate(Smi::FromInt(strict_mode_flag()))); |
| 2132 | 2080 |
| 2133 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP | 2081 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP |
| 2134 ? Runtime::kResolvePossiblyDirectEvalNoLookup | 2082 ? Runtime::kResolvePossiblyDirectEvalNoLookup |
| 2135 : Runtime::kResolvePossiblyDirectEval, 4); | 2083 : Runtime::kResolvePossiblyDirectEval, 4); |
| 2136 } | 2084 } |
| 2137 | 2085 |
| 2138 | 2086 |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2232 | 2180 |
| 2233 // If fast case code has been generated, emit code to push the | 2181 // If fast case code has been generated, emit code to push the |
| 2234 // function and receiver and have the slow path jump around this | 2182 // function and receiver and have the slow path jump around this |
| 2235 // code. | 2183 // code. |
| 2236 if (done.is_linked()) { | 2184 if (done.is_linked()) { |
| 2237 Label call; | 2185 Label call; |
| 2238 __ jmp(&call); | 2186 __ jmp(&call); |
| 2239 __ bind(&done); | 2187 __ bind(&done); |
| 2240 // Push function. | 2188 // Push function. |
| 2241 __ push(eax); | 2189 __ push(eax); |
| 2242 // Push global receiver. | 2190 // The receiver is implicitly the global receiver. Indicate this |
| 2243 __ mov(ebx, GlobalObjectOperand()); | 2191 // by passing the hole to the call function stub. |
| 2244 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); | 2192 __ push(Immediate(isolate()->factory()->the_hole_value())); |
| 2245 __ bind(&call); | 2193 __ bind(&call); |
| 2246 } | 2194 } |
| 2247 | 2195 |
| 2248 // The receiver is either the global receiver or an object found | 2196 // The receiver is either the global receiver or an object found |
| 2249 // by LoadContextSlot. That object could be the hole if the | 2197 // by LoadContextSlot. That object could be the hole if the |
| 2250 // receiver is implicitly the global object. | 2198 // receiver is implicitly the global object. |
| 2251 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); | 2199 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); |
| 2252 } else if (fun->AsProperty() != NULL) { | 2200 } else if (fun->AsProperty() != NULL) { |
| 2253 // Call to an object property. | 2201 // Call to an object property. |
| 2254 Property* prop = fun->AsProperty(); | 2202 Property* prop = fun->AsProperty(); |
| 2255 Literal* key = prop->key()->AsLiteral(); | 2203 Literal* key = prop->key()->AsLiteral(); |
| 2256 if (key != NULL && key->handle()->IsSymbol()) { | 2204 if (key != NULL && key->handle()->IsSymbol()) { |
| 2257 // Call to a named property, use call IC. | 2205 // Call to a named property, use call IC. |
| 2258 { PreservePositionScope scope(masm()->positions_recorder()); | 2206 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2259 VisitForStackValue(prop->obj()); | 2207 VisitForStackValue(prop->obj()); |
| 2260 } | 2208 } |
| 2261 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2209 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 2262 } else { | 2210 } else { |
| 2263 // Call to a keyed property. | 2211 // Call to a keyed property. |
| 2264 // For a synthetic property use keyed load IC followed by function call, | 2212 // For a synthetic property use keyed load IC followed by function call, |
| 2265 // for a regular property use keyed EmitCallIC. | 2213 // for a regular property use EmitKeyedCallWithIC. |
| 2266 if (prop->is_synthetic()) { | 2214 if (prop->is_synthetic()) { |
| 2267 // Do not visit the object and key subexpressions (they are shared | 2215 // Do not visit the object and key subexpressions (they are shared |
| 2268 // by all occurrences of the same rewritten parameter). | 2216 // by all occurrences of the same rewritten parameter). |
| 2269 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 2217 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 2270 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); | 2218 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); |
| 2271 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); | 2219 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); |
| 2272 MemOperand operand = EmitSlotSearch(slot, edx); | 2220 MemOperand operand = EmitSlotSearch(slot, edx); |
| 2273 __ mov(edx, operand); | 2221 __ mov(edx, operand); |
| 2274 | 2222 |
| 2275 ASSERT(prop->key()->AsLiteral() != NULL); | 2223 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2276 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); | 2224 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); |
| 2277 __ mov(eax, prop->key()->AsLiteral()->handle()); | 2225 __ mov(eax, prop->key()->AsLiteral()->handle()); |
| 2278 | 2226 |
| 2279 // Record source code position for IC call. | 2227 // Record source code position for IC call. |
| 2280 SetSourcePosition(prop->position()); | 2228 SetSourcePosition(prop->position()); |
| 2281 | 2229 |
| 2282 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 2230 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2283 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | 2231 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); |
| 2284 // Push result (function). | 2232 // Push result (function). |
| 2285 __ push(eax); | 2233 __ push(eax); |
| 2286 // Push Global receiver. | 2234 // Push Global receiver. |
| 2287 __ mov(ecx, GlobalObjectOperand()); | 2235 __ mov(ecx, GlobalObjectOperand()); |
| 2288 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); | 2236 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); |
| 2289 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); | 2237 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); |
| 2290 } else { | 2238 } else { |
| 2291 { PreservePositionScope scope(masm()->positions_recorder()); | 2239 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2292 VisitForStackValue(prop->obj()); | 2240 VisitForStackValue(prop->obj()); |
| 2293 } | 2241 } |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2390 | 2338 |
| 2391 VisitForAccumulatorValue(args->at(0)); | 2339 VisitForAccumulatorValue(args->at(0)); |
| 2392 | 2340 |
| 2393 Label materialize_true, materialize_false; | 2341 Label materialize_true, materialize_false; |
| 2394 Label* if_true = NULL; | 2342 Label* if_true = NULL; |
| 2395 Label* if_false = NULL; | 2343 Label* if_false = NULL; |
| 2396 Label* fall_through = NULL; | 2344 Label* fall_through = NULL; |
| 2397 context()->PrepareTest(&materialize_true, &materialize_false, | 2345 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2398 &if_true, &if_false, &fall_through); | 2346 &if_true, &if_false, &fall_through); |
| 2399 | 2347 |
| 2400 __ test(eax, Immediate(kSmiTagMask)); | 2348 __ JumpIfSmi(eax, if_false); |
| 2401 __ j(zero, if_false); | |
| 2402 __ cmp(eax, isolate()->factory()->null_value()); | 2349 __ cmp(eax, isolate()->factory()->null_value()); |
| 2403 __ j(equal, if_true); | 2350 __ j(equal, if_true); |
| 2404 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 2351 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2405 // Undetectable objects behave like undefined when tested with typeof. | 2352 // Undetectable objects behave like undefined when tested with typeof. |
| 2406 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset)); | 2353 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset)); |
| 2407 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 2354 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); |
| 2408 __ j(not_zero, if_false); | 2355 __ j(not_zero, if_false); |
| 2409 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 2356 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 2410 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); | 2357 __ cmp(ecx, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 2411 __ j(below, if_false); | 2358 __ j(below, if_false); |
| 2412 __ cmp(ecx, LAST_JS_OBJECT_TYPE); | 2359 __ cmp(ecx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 2413 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 2360 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2414 Split(below_equal, if_true, if_false, fall_through); | 2361 Split(below_equal, if_true, if_false, fall_through); |
| 2415 | 2362 |
| 2416 context()->Plug(if_true, if_false); | 2363 context()->Plug(if_true, if_false); |
| 2417 } | 2364 } |
| 2418 | 2365 |
| 2419 | 2366 |
| 2420 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { | 2367 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { |
| 2421 ASSERT(args->length() == 1); | 2368 ASSERT(args->length() == 1); |
| 2422 | 2369 |
| 2423 VisitForAccumulatorValue(args->at(0)); | 2370 VisitForAccumulatorValue(args->at(0)); |
| 2424 | 2371 |
| 2425 Label materialize_true, materialize_false; | 2372 Label materialize_true, materialize_false; |
| 2426 Label* if_true = NULL; | 2373 Label* if_true = NULL; |
| 2427 Label* if_false = NULL; | 2374 Label* if_false = NULL; |
| 2428 Label* fall_through = NULL; | 2375 Label* fall_through = NULL; |
| 2429 context()->PrepareTest(&materialize_true, &materialize_false, | 2376 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2430 &if_true, &if_false, &fall_through); | 2377 &if_true, &if_false, &fall_through); |
| 2431 | 2378 |
| 2432 __ test(eax, Immediate(kSmiTagMask)); | 2379 __ JumpIfSmi(eax, if_false); |
| 2433 __ j(equal, if_false); | 2380 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ebx); |
| 2434 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ebx); | |
| 2435 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 2381 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2436 Split(above_equal, if_true, if_false, fall_through); | 2382 Split(above_equal, if_true, if_false, fall_through); |
| 2437 | 2383 |
| 2438 context()->Plug(if_true, if_false); | 2384 context()->Plug(if_true, if_false); |
| 2439 } | 2385 } |
| 2440 | 2386 |
| 2441 | 2387 |
| 2442 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { | 2388 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { |
| 2443 ASSERT(args->length() == 1); | 2389 ASSERT(args->length() == 1); |
| 2444 | 2390 |
| 2445 VisitForAccumulatorValue(args->at(0)); | 2391 VisitForAccumulatorValue(args->at(0)); |
| 2446 | 2392 |
| 2447 Label materialize_true, materialize_false; | 2393 Label materialize_true, materialize_false; |
| 2448 Label* if_true = NULL; | 2394 Label* if_true = NULL; |
| 2449 Label* if_false = NULL; | 2395 Label* if_false = NULL; |
| 2450 Label* fall_through = NULL; | 2396 Label* fall_through = NULL; |
| 2451 context()->PrepareTest(&materialize_true, &materialize_false, | 2397 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2452 &if_true, &if_false, &fall_through); | 2398 &if_true, &if_false, &fall_through); |
| 2453 | 2399 |
| 2454 __ test(eax, Immediate(kSmiTagMask)); | 2400 __ JumpIfSmi(eax, if_false); |
| 2455 __ j(zero, if_false); | |
| 2456 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 2401 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2457 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset)); | 2402 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset)); |
| 2458 __ test(ebx, Immediate(1 << Map::kIsUndetectable)); | 2403 __ test(ebx, Immediate(1 << Map::kIsUndetectable)); |
| 2459 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 2404 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2460 Split(not_zero, if_true, if_false, fall_through); | 2405 Split(not_zero, if_true, if_false, fall_through); |
| 2461 | 2406 |
| 2462 context()->Plug(if_true, if_false); | 2407 context()->Plug(if_true, if_false); |
| 2463 } | 2408 } |
| 2464 | 2409 |
| 2465 | 2410 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2519 __ bind(&entry); | 2464 __ bind(&entry); |
| 2520 __ cmp(ebx, Operand(ecx)); | 2465 __ cmp(ebx, Operand(ecx)); |
| 2521 __ j(not_equal, &loop); | 2466 __ j(not_equal, &loop); |
| 2522 | 2467 |
| 2523 // Reload map as register ebx was used as temporary above. | 2468 // Reload map as register ebx was used as temporary above. |
| 2524 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 2469 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2525 | 2470 |
| 2526 // If a valueOf property is not found on the object check that it's | 2471 // If a valueOf property is not found on the object check that it's |
| 2527 // prototype is the un-modified String prototype. If not result is false. | 2472 // prototype is the un-modified String prototype. If not result is false. |
| 2528 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); | 2473 __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset)); |
| 2529 __ test(ecx, Immediate(kSmiTagMask)); | 2474 __ JumpIfSmi(ecx, if_false); |
| 2530 __ j(zero, if_false); | |
| 2531 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); | 2475 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); |
| 2532 __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 2476 __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 2533 __ mov(edx, | 2477 __ mov(edx, |
| 2534 FieldOperand(edx, GlobalObject::kGlobalContextOffset)); | 2478 FieldOperand(edx, GlobalObject::kGlobalContextOffset)); |
| 2535 __ cmp(ecx, | 2479 __ cmp(ecx, |
| 2536 ContextOperand(edx, | 2480 ContextOperand(edx, |
| 2537 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); | 2481 Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX)); |
| 2538 __ j(not_equal, if_false); | 2482 __ j(not_equal, if_false); |
| 2539 // Set the bit in the map to indicate that it has been checked safe for | 2483 // Set the bit in the map to indicate that it has been checked safe for |
| 2540 // default valueOf and set true result. | 2484 // default valueOf and set true result. |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2552 | 2496 |
| 2553 VisitForAccumulatorValue(args->at(0)); | 2497 VisitForAccumulatorValue(args->at(0)); |
| 2554 | 2498 |
| 2555 Label materialize_true, materialize_false; | 2499 Label materialize_true, materialize_false; |
| 2556 Label* if_true = NULL; | 2500 Label* if_true = NULL; |
| 2557 Label* if_false = NULL; | 2501 Label* if_false = NULL; |
| 2558 Label* fall_through = NULL; | 2502 Label* fall_through = NULL; |
| 2559 context()->PrepareTest(&materialize_true, &materialize_false, | 2503 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2560 &if_true, &if_false, &fall_through); | 2504 &if_true, &if_false, &fall_through); |
| 2561 | 2505 |
| 2562 __ test(eax, Immediate(kSmiTagMask)); | 2506 __ JumpIfSmi(eax, if_false); |
| 2563 __ j(zero, if_false); | |
| 2564 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); | 2507 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
| 2565 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 2508 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2566 Split(equal, if_true, if_false, fall_through); | 2509 Split(equal, if_true, if_false, fall_through); |
| 2567 | 2510 |
| 2568 context()->Plug(if_true, if_false); | 2511 context()->Plug(if_true, if_false); |
| 2569 } | 2512 } |
| 2570 | 2513 |
| 2571 | 2514 |
| 2572 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { | 2515 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) { |
| 2573 ASSERT(args->length() == 1); | 2516 ASSERT(args->length() == 1); |
| 2574 | 2517 |
| 2575 VisitForAccumulatorValue(args->at(0)); | 2518 VisitForAccumulatorValue(args->at(0)); |
| 2576 | 2519 |
| 2577 Label materialize_true, materialize_false; | 2520 Label materialize_true, materialize_false; |
| 2578 Label* if_true = NULL; | 2521 Label* if_true = NULL; |
| 2579 Label* if_false = NULL; | 2522 Label* if_false = NULL; |
| 2580 Label* fall_through = NULL; | 2523 Label* fall_through = NULL; |
| 2581 context()->PrepareTest(&materialize_true, &materialize_false, | 2524 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2582 &if_true, &if_false, &fall_through); | 2525 &if_true, &if_false, &fall_through); |
| 2583 | 2526 |
| 2584 __ test(eax, Immediate(kSmiTagMask)); | 2527 __ JumpIfSmi(eax, if_false); |
| 2585 __ j(equal, if_false); | |
| 2586 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); | 2528 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); |
| 2587 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 2529 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2588 Split(equal, if_true, if_false, fall_through); | 2530 Split(equal, if_true, if_false, fall_through); |
| 2589 | 2531 |
| 2590 context()->Plug(if_true, if_false); | 2532 context()->Plug(if_true, if_false); |
| 2591 } | 2533 } |
| 2592 | 2534 |
| 2593 | 2535 |
| 2594 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { | 2536 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) { |
| 2595 ASSERT(args->length() == 1); | 2537 ASSERT(args->length() == 1); |
| 2596 | 2538 |
| 2597 VisitForAccumulatorValue(args->at(0)); | 2539 VisitForAccumulatorValue(args->at(0)); |
| 2598 | 2540 |
| 2599 Label materialize_true, materialize_false; | 2541 Label materialize_true, materialize_false; |
| 2600 Label* if_true = NULL; | 2542 Label* if_true = NULL; |
| 2601 Label* if_false = NULL; | 2543 Label* if_false = NULL; |
| 2602 Label* fall_through = NULL; | 2544 Label* fall_through = NULL; |
| 2603 context()->PrepareTest(&materialize_true, &materialize_false, | 2545 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2604 &if_true, &if_false, &fall_through); | 2546 &if_true, &if_false, &fall_through); |
| 2605 | 2547 |
| 2606 __ test(eax, Immediate(kSmiTagMask)); | 2548 __ JumpIfSmi(eax, if_false); |
| 2607 __ j(equal, if_false); | |
| 2608 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx); | 2549 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx); |
| 2609 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 2550 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2610 Split(equal, if_true, if_false, fall_through); | 2551 Split(equal, if_true, if_false, fall_through); |
| 2611 | 2552 |
| 2612 context()->Plug(if_true, if_false); | 2553 context()->Plug(if_true, if_false); |
| 2613 } | 2554 } |
| 2614 | 2555 |
| 2615 | 2556 |
| 2616 | 2557 |
| 2617 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { | 2558 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2668 } | 2609 } |
| 2669 | 2610 |
| 2670 | 2611 |
| 2671 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2612 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
| 2672 ASSERT(args->length() == 1); | 2613 ASSERT(args->length() == 1); |
| 2673 | 2614 |
| 2674 // ArgumentsAccessStub expects the key in edx and the formal | 2615 // ArgumentsAccessStub expects the key in edx and the formal |
| 2675 // parameter count in eax. | 2616 // parameter count in eax. |
| 2676 VisitForAccumulatorValue(args->at(0)); | 2617 VisitForAccumulatorValue(args->at(0)); |
| 2677 __ mov(edx, eax); | 2618 __ mov(edx, eax); |
| 2678 __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters()))); | 2619 __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters()))); |
| 2679 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 2620 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 2680 __ CallStub(&stub); | 2621 __ CallStub(&stub); |
| 2681 context()->Plug(eax); | 2622 context()->Plug(eax); |
| 2682 } | 2623 } |
| 2683 | 2624 |
| 2684 | 2625 |
| 2685 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { | 2626 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { |
| 2686 ASSERT(args->length() == 0); | 2627 ASSERT(args->length() == 0); |
| 2687 | 2628 |
| 2688 Label exit; | 2629 Label exit; |
| 2689 // Get the number of formal parameters. | 2630 // Get the number of formal parameters. |
| 2690 __ SafeSet(eax, Immediate(Smi::FromInt(scope()->num_parameters()))); | 2631 __ SafeSet(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters()))); |
| 2691 | 2632 |
| 2692 // Check if the calling frame is an arguments adaptor frame. | 2633 // Check if the calling frame is an arguments adaptor frame. |
| 2693 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); | 2634 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); |
| 2694 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset), | 2635 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset), |
| 2695 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 2636 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
| 2696 __ j(not_equal, &exit); | 2637 __ j(not_equal, &exit); |
| 2697 | 2638 |
| 2698 // Arguments adaptor case: Read the arguments length from the | 2639 // Arguments adaptor case: Read the arguments length from the |
| 2699 // adaptor frame. | 2640 // adaptor frame. |
| 2700 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 2641 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2701 | 2642 |
| 2702 __ bind(&exit); | 2643 __ bind(&exit); |
| 2703 if (FLAG_debug_code) __ AbortIfNotSmi(eax); | 2644 if (FLAG_debug_code) __ AbortIfNotSmi(eax); |
| 2704 context()->Plug(eax); | 2645 context()->Plug(eax); |
| 2705 } | 2646 } |
| 2706 | 2647 |
| 2707 | 2648 |
| 2708 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) { | 2649 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) { |
| 2709 ASSERT(args->length() == 1); | 2650 ASSERT(args->length() == 1); |
| 2710 Label done, null, function, non_function_constructor; | 2651 Label done, null, function, non_function_constructor; |
| 2711 | 2652 |
| 2712 VisitForAccumulatorValue(args->at(0)); | 2653 VisitForAccumulatorValue(args->at(0)); |
| 2713 | 2654 |
| 2714 // If the object is a smi, we return null. | 2655 // If the object is a smi, we return null. |
| 2715 __ test(eax, Immediate(kSmiTagMask)); | 2656 __ JumpIfSmi(eax, &null); |
| 2716 __ j(zero, &null); | |
| 2717 | 2657 |
| 2718 // Check that the object is a JS object but take special care of JS | 2658 // Check that the object is a JS object but take special care of JS |
| 2719 // functions to make sure they have 'Function' as their class. | 2659 // functions to make sure they have 'Function' as their class. |
| 2720 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, eax); // Map is now in eax. | 2660 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax); |
| 2661 // Map is now in eax. |
| 2721 __ j(below, &null); | 2662 __ j(below, &null); |
| 2722 | 2663 |
| 2723 // As long as JS_FUNCTION_TYPE is the last instance type and it is | 2664 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and |
| 2724 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for | 2665 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after |
| 2725 // LAST_JS_OBJECT_TYPE. | 2666 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. |
| 2726 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 2667 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
| 2727 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | 2668 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == |
| 2728 __ CmpInstanceType(eax, JS_FUNCTION_TYPE); | 2669 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); |
| 2729 __ j(equal, &function); | 2670 __ CmpInstanceType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE); |
| 2671 __ j(above_equal, &function); |
| 2730 | 2672 |
| 2731 // Check if the constructor in the map is a function. | 2673 // Check if the constructor in the map is a function. |
| 2732 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset)); | 2674 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset)); |
| 2733 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); | 2675 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
| 2734 __ j(not_equal, &non_function_constructor); | 2676 __ j(not_equal, &non_function_constructor); |
| 2735 | 2677 |
| 2736 // eax now contains the constructor function. Grab the | 2678 // eax now contains the constructor function. Grab the |
| 2737 // instance class name from there. | 2679 // instance class name from there. |
| 2738 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); | 2680 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); |
| 2739 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); | 2681 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset)); |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2857 } | 2799 } |
| 2858 | 2800 |
| 2859 | 2801 |
| 2860 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) { | 2802 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) { |
| 2861 ASSERT(args->length() == 1); | 2803 ASSERT(args->length() == 1); |
| 2862 | 2804 |
| 2863 VisitForAccumulatorValue(args->at(0)); // Load the object. | 2805 VisitForAccumulatorValue(args->at(0)); // Load the object. |
| 2864 | 2806 |
| 2865 Label done; | 2807 Label done; |
| 2866 // If the object is a smi return the object. | 2808 // If the object is a smi return the object. |
| 2867 __ test(eax, Immediate(kSmiTagMask)); | 2809 __ JumpIfSmi(eax, &done, Label::kNear); |
| 2868 __ j(zero, &done, Label::kNear); | |
| 2869 // If the object is not a value type, return the object. | 2810 // If the object is not a value type, return the object. |
| 2870 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx); | 2811 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx); |
| 2871 __ j(not_equal, &done, Label::kNear); | 2812 __ j(not_equal, &done, Label::kNear); |
| 2872 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); | 2813 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); |
| 2873 | 2814 |
| 2874 __ bind(&done); | 2815 __ bind(&done); |
| 2875 context()->Plug(eax); | 2816 context()->Plug(eax); |
| 2876 } | 2817 } |
| 2877 | 2818 |
| 2878 | 2819 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2894 | 2835 |
| 2895 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { | 2836 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { |
| 2896 ASSERT(args->length() == 2); | 2837 ASSERT(args->length() == 2); |
| 2897 | 2838 |
| 2898 VisitForStackValue(args->at(0)); // Load the object. | 2839 VisitForStackValue(args->at(0)); // Load the object. |
| 2899 VisitForAccumulatorValue(args->at(1)); // Load the value. | 2840 VisitForAccumulatorValue(args->at(1)); // Load the value. |
| 2900 __ pop(ebx); // eax = value. ebx = object. | 2841 __ pop(ebx); // eax = value. ebx = object. |
| 2901 | 2842 |
| 2902 Label done; | 2843 Label done; |
| 2903 // If the object is a smi, return the value. | 2844 // If the object is a smi, return the value. |
| 2904 __ test(ebx, Immediate(kSmiTagMask)); | 2845 __ JumpIfSmi(ebx, &done, Label::kNear); |
| 2905 __ j(zero, &done, Label::kNear); | |
| 2906 | 2846 |
| 2907 // If the object is not a value type, return the value. | 2847 // If the object is not a value type, return the value. |
| 2908 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx); | 2848 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx); |
| 2909 __ j(not_equal, &done, Label::kNear); | 2849 __ j(not_equal, &done, Label::kNear); |
| 2910 | 2850 |
| 2911 // Store the value. | 2851 // Store the value. |
| 2912 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax); | 2852 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax); |
| 2913 | 2853 |
| 2914 // Update the write barrier. Save the value as it will be | 2854 // Update the write barrier. Save the value as it will be |
| 2915 // overwritten by the write barrier code and is needed afterward. | 2855 // overwritten by the write barrier code and is needed afterward. |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3118 | 3058 |
| 3119 int arg_count = args->length() - 2; // 2 ~ receiver and function. | 3059 int arg_count = args->length() - 2; // 2 ~ receiver and function. |
| 3120 for (int i = 0; i < arg_count + 1; ++i) { | 3060 for (int i = 0; i < arg_count + 1; ++i) { |
| 3121 VisitForStackValue(args->at(i)); | 3061 VisitForStackValue(args->at(i)); |
| 3122 } | 3062 } |
| 3123 VisitForAccumulatorValue(args->last()); // Function. | 3063 VisitForAccumulatorValue(args->last()); // Function. |
| 3124 | 3064 |
| 3125 // InvokeFunction requires the function in edi. Move it in there. | 3065 // InvokeFunction requires the function in edi. Move it in there. |
| 3126 __ mov(edi, result_register()); | 3066 __ mov(edi, result_register()); |
| 3127 ParameterCount count(arg_count); | 3067 ParameterCount count(arg_count); |
| 3128 __ InvokeFunction(edi, count, CALL_FUNCTION); | 3068 __ InvokeFunction(edi, count, CALL_FUNCTION, |
| 3069 NullCallWrapper(), CALL_AS_METHOD); |
| 3129 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3070 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3130 context()->Plug(eax); | 3071 context()->Plug(eax); |
| 3131 } | 3072 } |
| 3132 | 3073 |
| 3133 | 3074 |
| 3134 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) { | 3075 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) { |
| 3135 // Load the arguments on the stack and call the stub. | 3076 // Load the arguments on the stack and call the stub. |
| 3136 RegExpConstructResultStub stub; | 3077 RegExpConstructResultStub stub; |
| 3137 ASSERT(args->length() == 3); | 3078 ASSERT(args->length() == 3); |
| 3138 VisitForStackValue(args->at(0)); | 3079 VisitForStackValue(args->at(0)); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 3169 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset)); | 3110 __ mov(elements, FieldOperand(object, JSObject::kElementsOffset)); |
| 3170 __ cmp(FieldOperand(elements, HeapObject::kMapOffset), | 3111 __ cmp(FieldOperand(elements, HeapObject::kMapOffset), |
| 3171 Immediate(isolate()->factory()->fixed_array_map())); | 3112 Immediate(isolate()->factory()->fixed_array_map())); |
| 3172 __ j(not_equal, &slow_case); | 3113 __ j(not_equal, &slow_case); |
| 3173 | 3114 |
| 3174 // Check that both indices are smis. | 3115 // Check that both indices are smis. |
| 3175 __ mov(index_1, Operand(esp, 1 * kPointerSize)); | 3116 __ mov(index_1, Operand(esp, 1 * kPointerSize)); |
| 3176 __ mov(index_2, Operand(esp, 0)); | 3117 __ mov(index_2, Operand(esp, 0)); |
| 3177 __ mov(temp, index_1); | 3118 __ mov(temp, index_1); |
| 3178 __ or_(temp, Operand(index_2)); | 3119 __ or_(temp, Operand(index_2)); |
| 3179 __ test(temp, Immediate(kSmiTagMask)); | 3120 __ JumpIfNotSmi(temp, &slow_case); |
| 3180 __ j(not_zero, &slow_case); | |
| 3181 | 3121 |
| 3182 // Check that both indices are valid. | 3122 // Check that both indices are valid. |
| 3183 __ mov(temp, FieldOperand(object, JSArray::kLengthOffset)); | 3123 __ mov(temp, FieldOperand(object, JSArray::kLengthOffset)); |
| 3184 __ cmp(temp, Operand(index_1)); | 3124 __ cmp(temp, Operand(index_1)); |
| 3185 __ j(below_equal, &slow_case); | 3125 __ j(below_equal, &slow_case); |
| 3186 __ cmp(temp, Operand(index_2)); | 3126 __ cmp(temp, Operand(index_2)); |
| 3187 __ j(below_equal, &slow_case); | 3127 __ j(below_equal, &slow_case); |
| 3188 | 3128 |
| 3189 // Bring addresses into index1 and index2. | 3129 // Bring addresses into index1 and index2. |
| 3190 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1)); | 3130 __ lea(index_1, CodeGenerator::FixedArrayElementOperand(elements, index_1)); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3288 VisitForStackValue(args->at(0)); | 3228 VisitForStackValue(args->at(0)); |
| 3289 VisitForAccumulatorValue(args->at(1)); | 3229 VisitForAccumulatorValue(args->at(1)); |
| 3290 __ pop(left); | 3230 __ pop(left); |
| 3291 | 3231 |
| 3292 Label done, fail, ok; | 3232 Label done, fail, ok; |
| 3293 __ cmp(left, Operand(right)); | 3233 __ cmp(left, Operand(right)); |
| 3294 __ j(equal, &ok); | 3234 __ j(equal, &ok); |
| 3295 // Fail if either is a non-HeapObject. | 3235 // Fail if either is a non-HeapObject. |
| 3296 __ mov(tmp, left); | 3236 __ mov(tmp, left); |
| 3297 __ and_(Operand(tmp), right); | 3237 __ and_(Operand(tmp), right); |
| 3298 __ test(Operand(tmp), Immediate(kSmiTagMask)); | 3238 __ JumpIfSmi(tmp, &fail); |
| 3299 __ j(zero, &fail); | |
| 3300 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset)); | 3239 __ mov(tmp, FieldOperand(left, HeapObject::kMapOffset)); |
| 3301 __ CmpInstanceType(tmp, JS_REGEXP_TYPE); | 3240 __ CmpInstanceType(tmp, JS_REGEXP_TYPE); |
| 3302 __ j(not_equal, &fail); | 3241 __ j(not_equal, &fail); |
| 3303 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset)); | 3242 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset)); |
| 3304 __ j(not_equal, &fail); | 3243 __ j(not_equal, &fail); |
| 3305 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset)); | 3244 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset)); |
| 3306 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset)); | 3245 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset)); |
| 3307 __ j(equal, &ok); | 3246 __ j(equal, &ok); |
| 3308 __ bind(&fail); | 3247 __ bind(&fail); |
| 3309 __ mov(eax, Immediate(isolate()->factory()->false_value())); | 3248 __ mov(eax, Immediate(isolate()->factory()->false_value())); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3381 Register array_length = edi; | 3320 Register array_length = edi; |
| 3382 Register result_pos = no_reg; // Will be edi. | 3321 Register result_pos = no_reg; // Will be edi. |
| 3383 | 3322 |
| 3384 // Separator operand is already pushed. | 3323 // Separator operand is already pushed. |
| 3385 Operand separator_operand = Operand(esp, 2 * kPointerSize); | 3324 Operand separator_operand = Operand(esp, 2 * kPointerSize); |
| 3386 Operand result_operand = Operand(esp, 1 * kPointerSize); | 3325 Operand result_operand = Operand(esp, 1 * kPointerSize); |
| 3387 Operand array_length_operand = Operand(esp, 0); | 3326 Operand array_length_operand = Operand(esp, 0); |
| 3388 __ sub(Operand(esp), Immediate(2 * kPointerSize)); | 3327 __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
| 3389 __ cld(); | 3328 __ cld(); |
| 3390 // Check that the array is a JSArray | 3329 // Check that the array is a JSArray |
| 3391 __ test(array, Immediate(kSmiTagMask)); | 3330 __ JumpIfSmi(array, &bailout); |
| 3392 __ j(zero, &bailout); | |
| 3393 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); | 3331 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); |
| 3394 __ j(not_equal, &bailout); | 3332 __ j(not_equal, &bailout); |
| 3395 | 3333 |
| 3396 // Check that the array has fast elements. | 3334 // Check that the array has fast elements. |
| 3397 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), | 3335 __ CheckFastElements(scratch, &bailout); |
| 3398 1 << Map::kHasFastElements); | |
| 3399 __ j(zero, &bailout); | |
| 3400 | 3336 |
| 3401 // If the array has length zero, return the empty string. | 3337 // If the array has length zero, return the empty string. |
| 3402 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); | 3338 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); |
| 3403 __ SmiUntag(array_length); | 3339 __ SmiUntag(array_length); |
| 3404 __ j(not_zero, &non_trivial_array); | 3340 __ j(not_zero, &non_trivial_array); |
| 3405 __ mov(result_operand, isolate()->factory()->empty_string()); | 3341 __ mov(result_operand, isolate()->factory()->empty_string()); |
| 3406 __ jmp(&done); | 3342 __ jmp(&done); |
| 3407 | 3343 |
| 3408 // Save the array length. | 3344 // Save the array length. |
| 3409 __ bind(&non_trivial_array); | 3345 __ bind(&non_trivial_array); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3425 // scratch, string_length, elements. | 3361 // scratch, string_length, elements. |
| 3426 if (FLAG_debug_code) { | 3362 if (FLAG_debug_code) { |
| 3427 __ cmp(index, Operand(array_length)); | 3363 __ cmp(index, Operand(array_length)); |
| 3428 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin"); | 3364 __ Assert(less, "No empty arrays here in EmitFastAsciiArrayJoin"); |
| 3429 } | 3365 } |
| 3430 __ bind(&loop); | 3366 __ bind(&loop); |
| 3431 __ mov(string, FieldOperand(elements, | 3367 __ mov(string, FieldOperand(elements, |
| 3432 index, | 3368 index, |
| 3433 times_pointer_size, | 3369 times_pointer_size, |
| 3434 FixedArray::kHeaderSize)); | 3370 FixedArray::kHeaderSize)); |
| 3435 __ test(string, Immediate(kSmiTagMask)); | 3371 __ JumpIfSmi(string, &bailout); |
| 3436 __ j(zero, &bailout); | |
| 3437 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); | 3372 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
| 3438 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 3373 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 3439 __ and_(scratch, Immediate( | 3374 __ and_(scratch, Immediate( |
| 3440 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 3375 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
| 3441 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 3376 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); |
| 3442 __ j(not_equal, &bailout); | 3377 __ j(not_equal, &bailout); |
| 3443 __ add(string_length, | 3378 __ add(string_length, |
| 3444 FieldOperand(string, SeqAsciiString::kLengthOffset)); | 3379 FieldOperand(string, SeqAsciiString::kLengthOffset)); |
| 3445 __ j(overflow, &bailout); | 3380 __ j(overflow, &bailout); |
| 3446 __ add(Operand(index), Immediate(1)); | 3381 __ add(Operand(index), Immediate(1)); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3459 // End of array_length live range. | 3394 // End of array_length live range. |
| 3460 result_pos = array_length; | 3395 result_pos = array_length; |
| 3461 array_length = no_reg; | 3396 array_length = no_reg; |
| 3462 | 3397 |
| 3463 // Live registers: | 3398 // Live registers: |
| 3464 // string_length: Sum of string lengths, as a smi. | 3399 // string_length: Sum of string lengths, as a smi. |
| 3465 // elements: FixedArray of strings. | 3400 // elements: FixedArray of strings. |
| 3466 | 3401 |
| 3467 // Check that the separator is a flat ASCII string. | 3402 // Check that the separator is a flat ASCII string. |
| 3468 __ mov(string, separator_operand); | 3403 __ mov(string, separator_operand); |
| 3469 __ test(string, Immediate(kSmiTagMask)); | 3404 __ JumpIfSmi(string, &bailout); |
| 3470 __ j(zero, &bailout); | |
| 3471 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); | 3405 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
| 3472 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 3406 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 3473 __ and_(scratch, Immediate( | 3407 __ and_(scratch, Immediate( |
| 3474 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 3408 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
| 3475 __ cmp(scratch, ASCII_STRING_TYPE); | 3409 __ cmp(scratch, ASCII_STRING_TYPE); |
| 3476 __ j(not_equal, &bailout); | 3410 __ j(not_equal, &bailout); |
| 3477 | 3411 |
| 3478 // Add (separator length times array_length) - separator length | 3412 // Add (separator length times array_length) - separator length |
| 3479 // to string_length. | 3413 // to string_length. |
| 3480 __ mov(scratch, separator_operand); | 3414 __ mov(scratch, separator_operand); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3617 __ bind(&done); | 3551 __ bind(&done); |
| 3618 __ mov(eax, result_operand); | 3552 __ mov(eax, result_operand); |
| 3619 // Drop temp values from the stack, and restore context register. | 3553 // Drop temp values from the stack, and restore context register. |
| 3620 __ add(Operand(esp), Immediate(3 * kPointerSize)); | 3554 __ add(Operand(esp), Immediate(3 * kPointerSize)); |
| 3621 | 3555 |
| 3622 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3556 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3623 context()->Plug(eax); | 3557 context()->Plug(eax); |
| 3624 } | 3558 } |
| 3625 | 3559 |
| 3626 | 3560 |
| 3561 void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>* args) { |
| 3562 ASSERT(args->length() == 1); |
| 3563 |
| 3564 // Load the function into eax. |
| 3565 VisitForAccumulatorValue(args->at(0)); |
| 3566 |
| 3567 // Prepare for the test. |
| 3568 Label materialize_true, materialize_false; |
| 3569 Label* if_true = NULL; |
| 3570 Label* if_false = NULL; |
| 3571 Label* fall_through = NULL; |
| 3572 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3573 &if_true, &if_false, &fall_through); |
| 3574 |
| 3575 // Test for strict mode function. |
| 3576 __ mov(ecx, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset)); |
| 3577 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset), |
| 3578 1 << SharedFunctionInfo::kStrictModeBitWithinByte); |
| 3579 __ j(not_equal, if_true); |
| 3580 |
| 3581 // Test for native function. |
| 3582 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset), |
| 3583 1 << SharedFunctionInfo::kNativeBitWithinByte); |
| 3584 __ j(not_equal, if_true); |
| 3585 |
| 3586 // Not native or strict-mode function. |
| 3587 __ jmp(if_false); |
| 3588 |
| 3589 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3590 context()->Plug(if_true, if_false); |
| 3591 } |
| 3592 |
| 3593 |
| 3627 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 3594 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 3628 Handle<String> name = expr->name(); | 3595 Handle<String> name = expr->name(); |
| 3629 if (name->length() > 0 && name->Get(0) == '_') { | 3596 if (name->length() > 0 && name->Get(0) == '_') { |
| 3630 Comment cmnt(masm_, "[ InlineRuntimeCall"); | 3597 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
| 3631 EmitInlineRuntimeCall(expr); | 3598 EmitInlineRuntimeCall(expr); |
| 3632 return; | 3599 return; |
| 3633 } | 3600 } |
| 3634 | 3601 |
| 3635 Comment cmnt(masm_, "[ CallRuntime"); | 3602 Comment cmnt(masm_, "[ CallRuntime"); |
| 3636 ZoneList<Expression*>* args = expr->arguments(); | 3603 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3647 VisitForStackValue(args->at(i)); | 3614 VisitForStackValue(args->at(i)); |
| 3648 } | 3615 } |
| 3649 | 3616 |
| 3650 if (expr->is_jsruntime()) { | 3617 if (expr->is_jsruntime()) { |
| 3651 // Call the JS runtime function via a call IC. | 3618 // Call the JS runtime function via a call IC. |
| 3652 __ Set(ecx, Immediate(expr->name())); | 3619 __ Set(ecx, Immediate(expr->name())); |
| 3653 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 3620 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 3654 RelocInfo::Mode mode = RelocInfo::CODE_TARGET; | 3621 RelocInfo::Mode mode = RelocInfo::CODE_TARGET; |
| 3655 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize( | 3622 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize( |
| 3656 arg_count, in_loop, mode); | 3623 arg_count, in_loop, mode); |
| 3657 EmitCallIC(ic, mode, expr->id()); | 3624 __ call(ic, mode, expr->id()); |
| 3658 // Restore context register. | 3625 // Restore context register. |
| 3659 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3626 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3660 } else { | 3627 } else { |
| 3661 // Call the C runtime function. | 3628 // Call the C runtime function. |
| 3662 __ CallRuntime(expr->function(), arg_count); | 3629 __ CallRuntime(expr->function(), arg_count); |
| 3663 } | 3630 } |
| 3664 context()->Plug(eax); | 3631 context()->Plug(eax); |
| 3665 } | 3632 } |
| 3666 | 3633 |
| 3667 | 3634 |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3752 } | 3719 } |
| 3753 __ CallRuntime(Runtime::kTypeof, 1); | 3720 __ CallRuntime(Runtime::kTypeof, 1); |
| 3754 context()->Plug(eax); | 3721 context()->Plug(eax); |
| 3755 break; | 3722 break; |
| 3756 } | 3723 } |
| 3757 | 3724 |
| 3758 case Token::ADD: { | 3725 case Token::ADD: { |
| 3759 Comment cmt(masm_, "[ UnaryOperation (ADD)"); | 3726 Comment cmt(masm_, "[ UnaryOperation (ADD)"); |
| 3760 VisitForAccumulatorValue(expr->expression()); | 3727 VisitForAccumulatorValue(expr->expression()); |
| 3761 Label no_conversion; | 3728 Label no_conversion; |
| 3762 __ test(result_register(), Immediate(kSmiTagMask)); | 3729 __ JumpIfSmi(result_register(), &no_conversion); |
| 3763 __ j(zero, &no_conversion); | |
| 3764 ToNumberStub convert_stub; | 3730 ToNumberStub convert_stub; |
| 3765 __ CallStub(&convert_stub); | 3731 __ CallStub(&convert_stub); |
| 3766 __ bind(&no_conversion); | 3732 __ bind(&no_conversion); |
| 3767 context()->Plug(result_register()); | 3733 context()->Plug(result_register()); |
| 3768 break; | 3734 break; |
| 3769 } | 3735 } |
| 3770 | 3736 |
| 3771 case Token::SUB: | 3737 case Token::SUB: |
| 3772 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)"); | 3738 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)"); |
| 3773 break; | 3739 break; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3787 // TODO(svenpanne): Allowing format strings in Comment would be nice here... | 3753 // TODO(svenpanne): Allowing format strings in Comment would be nice here... |
| 3788 Comment cmt(masm_, comment); | 3754 Comment cmt(masm_, comment); |
| 3789 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); | 3755 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); |
| 3790 UnaryOverwriteMode overwrite = | 3756 UnaryOverwriteMode overwrite = |
| 3791 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; | 3757 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; |
| 3792 UnaryOpStub stub(expr->op(), overwrite); | 3758 UnaryOpStub stub(expr->op(), overwrite); |
| 3793 // UnaryOpStub expects the argument to be in the | 3759 // UnaryOpStub expects the argument to be in the |
| 3794 // accumulator register eax. | 3760 // accumulator register eax. |
| 3795 VisitForAccumulatorValue(expr->expression()); | 3761 VisitForAccumulatorValue(expr->expression()); |
| 3796 SetSourcePosition(expr->position()); | 3762 SetSourcePosition(expr->position()); |
| 3797 EmitCallIC(stub.GetCode(), NULL, expr->id()); | 3763 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| 3798 context()->Plug(eax); | 3764 context()->Plug(eax); |
| 3799 } | 3765 } |
| 3800 | 3766 |
| 3801 | 3767 |
| 3802 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { | 3768 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { |
| 3803 Comment cmnt(masm_, "[ CountOperation"); | 3769 Comment cmnt(masm_, "[ CountOperation"); |
| 3804 SetSourcePosition(expr->position()); | 3770 SetSourcePosition(expr->position()); |
| 3805 | 3771 |
| 3806 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 3772 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 3807 // as the left-hand side. | 3773 // as the left-hand side. |
| 3808 if (!expr->expression()->IsValidLeftHandSide()) { | 3774 if (!expr->expression()->IsValidLeftHandSide()) { |
| 3809 VisitForEffect(expr->expression()); | 3775 VisitForEffect(expr->expression()); |
| 3810 return; | 3776 return; |
| 3811 } | 3777 } |
| 3812 | 3778 |
| 3813 // Expression can only be a property, a global or a (parameter or local) | 3779 // Expression can only be a property, a global or a (parameter or local) |
| 3814 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 3780 // slot. |
| 3815 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 3781 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 3816 LhsKind assign_type = VARIABLE; | 3782 LhsKind assign_type = VARIABLE; |
| 3817 Property* prop = expr->expression()->AsProperty(); | 3783 Property* prop = expr->expression()->AsProperty(); |
| 3818 // In case of a property we use the uninitialized expression context | 3784 // In case of a property we use the uninitialized expression context |
| 3819 // of the key to detect a named property. | 3785 // of the key to detect a named property. |
| 3820 if (prop != NULL) { | 3786 if (prop != NULL) { |
| 3821 assign_type = | 3787 assign_type = |
| 3822 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 3788 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
| 3823 } | 3789 } |
| 3824 | 3790 |
| 3825 // Evaluate expression and get value. | 3791 // Evaluate expression and get value. |
| 3826 if (assign_type == VARIABLE) { | 3792 if (assign_type == VARIABLE) { |
| 3827 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 3793 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 3828 AccumulatorValueContext context(this); | 3794 AccumulatorValueContext context(this); |
| 3829 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); | 3795 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); |
| 3830 } else { | 3796 } else { |
| 3831 // Reserve space for result of postfix operation. | 3797 // Reserve space for result of postfix operation. |
| 3832 if (expr->is_postfix() && !context()->IsEffect()) { | 3798 if (expr->is_postfix() && !context()->IsEffect()) { |
| 3833 __ push(Immediate(Smi::FromInt(0))); | 3799 __ push(Immediate(Smi::FromInt(0))); |
| 3834 } | 3800 } |
| 3835 if (assign_type == NAMED_PROPERTY) { | 3801 if (assign_type == NAMED_PROPERTY) { |
| 3836 // Put the object both on the stack and in the accumulator. | 3802 // Put the object both on the stack and in the accumulator. |
| 3837 VisitForAccumulatorValue(prop->obj()); | 3803 VisitForAccumulatorValue(prop->obj()); |
| 3838 __ push(eax); | 3804 __ push(eax); |
| 3839 EmitNamedPropertyLoad(prop); | 3805 EmitNamedPropertyLoad(prop); |
| 3840 } else { | 3806 } else { |
| 3841 if (prop->is_arguments_access()) { | 3807 VisitForStackValue(prop->obj()); |
| 3842 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); | 3808 VisitForAccumulatorValue(prop->key()); |
| 3843 MemOperand slot_operand = | |
| 3844 EmitSlotSearch(obj_proxy->var()->AsSlot(), ecx); | |
| 3845 __ push(slot_operand); | |
| 3846 __ SafeSet(eax, Immediate(prop->key()->AsLiteral()->handle())); | |
| 3847 } else { | |
| 3848 VisitForStackValue(prop->obj()); | |
| 3849 VisitForAccumulatorValue(prop->key()); | |
| 3850 } | |
| 3851 __ mov(edx, Operand(esp, 0)); | 3809 __ mov(edx, Operand(esp, 0)); |
| 3852 __ push(eax); | 3810 __ push(eax); |
| 3853 EmitKeyedPropertyLoad(prop); | 3811 EmitKeyedPropertyLoad(prop); |
| 3854 } | 3812 } |
| 3855 } | 3813 } |
| 3856 | 3814 |
| 3857 // We need a second deoptimization point after loading the value | 3815 // We need a second deoptimization point after loading the value |
| 3858 // in case evaluating the property load my have a side effect. | 3816 // in case evaluating the property load my have a side effect. |
| 3859 if (assign_type == VARIABLE) { | 3817 if (assign_type == VARIABLE) { |
| 3860 PrepareForBailout(expr->expression(), TOS_REG); | 3818 PrepareForBailout(expr->expression(), TOS_REG); |
| 3861 } else { | 3819 } else { |
| 3862 PrepareForBailoutForId(expr->CountId(), TOS_REG); | 3820 PrepareForBailoutForId(expr->CountId(), TOS_REG); |
| 3863 } | 3821 } |
| 3864 | 3822 |
| 3865 // Call ToNumber only if operand is not a smi. | 3823 // Call ToNumber only if operand is not a smi. |
| 3866 Label no_conversion; | 3824 Label no_conversion; |
| 3867 if (ShouldInlineSmiCase(expr->op())) { | 3825 if (ShouldInlineSmiCase(expr->op())) { |
| 3868 __ test(eax, Immediate(kSmiTagMask)); | 3826 __ JumpIfSmi(eax, &no_conversion, Label::kNear); |
| 3869 __ j(zero, &no_conversion, Label::kNear); | |
| 3870 } | 3827 } |
| 3871 ToNumberStub convert_stub; | 3828 ToNumberStub convert_stub; |
| 3872 __ CallStub(&convert_stub); | 3829 __ CallStub(&convert_stub); |
| 3873 __ bind(&no_conversion); | 3830 __ bind(&no_conversion); |
| 3874 | 3831 |
| 3875 // Save result for postfix expressions. | 3832 // Save result for postfix expressions. |
| 3876 if (expr->is_postfix()) { | 3833 if (expr->is_postfix()) { |
| 3877 if (!context()->IsEffect()) { | 3834 if (!context()->IsEffect()) { |
| 3878 // Save the result on the stack. If we have a named or keyed property | 3835 // Save the result on the stack. If we have a named or keyed property |
| 3879 // we store the result under the receiver that is currently on top | 3836 // we store the result under the receiver that is currently on top |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3916 } | 3873 } |
| 3917 } | 3874 } |
| 3918 | 3875 |
| 3919 // Record position before stub call. | 3876 // Record position before stub call. |
| 3920 SetSourcePosition(expr->position()); | 3877 SetSourcePosition(expr->position()); |
| 3921 | 3878 |
| 3922 // Call stub for +1/-1. | 3879 // Call stub for +1/-1. |
| 3923 __ mov(edx, eax); | 3880 __ mov(edx, eax); |
| 3924 __ mov(eax, Immediate(Smi::FromInt(1))); | 3881 __ mov(eax, Immediate(Smi::FromInt(1))); |
| 3925 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE); | 3882 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE); |
| 3926 EmitCallIC(stub.GetCode(), &patch_site, expr->CountId()); | 3883 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId()); |
| 3884 patch_site.EmitPatchInfo(); |
| 3927 __ bind(&done); | 3885 __ bind(&done); |
| 3928 | 3886 |
| 3929 // Store the value returned in eax. | 3887 // Store the value returned in eax. |
| 3930 switch (assign_type) { | 3888 switch (assign_type) { |
| 3931 case VARIABLE: | 3889 case VARIABLE: |
| 3932 if (expr->is_postfix()) { | 3890 if (expr->is_postfix()) { |
| 3933 // Perform the assignment as if via '='. | 3891 // Perform the assignment as if via '='. |
| 3934 { EffectContext context(this); | 3892 { EffectContext context(this); |
| 3935 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3893 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 3936 Token::ASSIGN); | 3894 Token::ASSIGN); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3949 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3907 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3950 context()->Plug(eax); | 3908 context()->Plug(eax); |
| 3951 } | 3909 } |
| 3952 break; | 3910 break; |
| 3953 case NAMED_PROPERTY: { | 3911 case NAMED_PROPERTY: { |
| 3954 __ mov(ecx, prop->key()->AsLiteral()->handle()); | 3912 __ mov(ecx, prop->key()->AsLiteral()->handle()); |
| 3955 __ pop(edx); | 3913 __ pop(edx); |
| 3956 Handle<Code> ic = is_strict_mode() | 3914 Handle<Code> ic = is_strict_mode() |
| 3957 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 3915 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 3958 : isolate()->builtins()->StoreIC_Initialize(); | 3916 : isolate()->builtins()->StoreIC_Initialize(); |
| 3959 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 3917 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 3960 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3918 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3961 if (expr->is_postfix()) { | 3919 if (expr->is_postfix()) { |
| 3962 if (!context()->IsEffect()) { | 3920 if (!context()->IsEffect()) { |
| 3963 context()->PlugTOS(); | 3921 context()->PlugTOS(); |
| 3964 } | 3922 } |
| 3965 } else { | 3923 } else { |
| 3966 context()->Plug(eax); | 3924 context()->Plug(eax); |
| 3967 } | 3925 } |
| 3968 break; | 3926 break; |
| 3969 } | 3927 } |
| 3970 case KEYED_PROPERTY: { | 3928 case KEYED_PROPERTY: { |
| 3971 __ pop(ecx); | 3929 __ pop(ecx); |
| 3972 __ pop(edx); | 3930 __ pop(edx); |
| 3973 Handle<Code> ic = is_strict_mode() | 3931 Handle<Code> ic = is_strict_mode() |
| 3974 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 3932 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 3975 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 3933 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 3976 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 3934 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 3977 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3935 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3978 if (expr->is_postfix()) { | 3936 if (expr->is_postfix()) { |
| 3979 // Result is on the stack | 3937 // Result is on the stack |
| 3980 if (!context()->IsEffect()) { | 3938 if (!context()->IsEffect()) { |
| 3981 context()->PlugTOS(); | 3939 context()->PlugTOS(); |
| 3982 } | 3940 } |
| 3983 } else { | 3941 } else { |
| 3984 context()->Plug(eax); | 3942 context()->Plug(eax); |
| 3985 } | 3943 } |
| 3986 break; | 3944 break; |
| 3987 } | 3945 } |
| 3988 } | 3946 } |
| 3989 } | 3947 } |
| 3990 | 3948 |
| 3991 | 3949 |
| 3992 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 3950 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 3993 VariableProxy* proxy = expr->AsVariableProxy(); | 3951 VariableProxy* proxy = expr->AsVariableProxy(); |
| 3994 ASSERT(!context()->IsEffect()); | 3952 ASSERT(!context()->IsEffect()); |
| 3995 ASSERT(!context()->IsTest()); | 3953 ASSERT(!context()->IsTest()); |
| 3996 | 3954 |
| 3997 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { | 3955 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { |
| 3998 Comment cmnt(masm_, "Global variable"); | 3956 Comment cmnt(masm_, "Global variable"); |
| 3999 __ mov(eax, GlobalObjectOperand()); | 3957 __ mov(eax, GlobalObjectOperand()); |
| 4000 __ mov(ecx, Immediate(proxy->name())); | 3958 __ mov(ecx, Immediate(proxy->name())); |
| 4001 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 3959 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 4002 // Use a regular load, not a contextual load, to avoid a reference | 3960 // Use a regular load, not a contextual load, to avoid a reference |
| 4003 // error. | 3961 // error. |
| 4004 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 3962 __ call(ic); |
| 4005 PrepareForBailout(expr, TOS_REG); | 3963 PrepareForBailout(expr, TOS_REG); |
| 4006 context()->Plug(eax); | 3964 context()->Plug(eax); |
| 4007 } else if (proxy != NULL && | 3965 } else if (proxy != NULL && |
| 4008 proxy->var()->AsSlot() != NULL && | 3966 proxy->var()->AsSlot() != NULL && |
| 4009 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { | 3967 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { |
| 4010 Label done, slow; | 3968 Label done, slow; |
| 4011 | 3969 |
| 4012 // Generate code for loading from variables potentially shadowed | 3970 // Generate code for loading from variables potentially shadowed |
| 4013 // by eval-introduced variables. | 3971 // by eval-introduced variables. |
| 4014 Slot* slot = proxy->var()->AsSlot(); | 3972 Slot* slot = proxy->var()->AsSlot(); |
| 4015 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); | 3973 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); |
| 4016 | 3974 |
| 4017 __ bind(&slow); | 3975 __ bind(&slow); |
| 4018 __ push(esi); | 3976 __ push(esi); |
| 4019 __ push(Immediate(proxy->name())); | 3977 __ push(Immediate(proxy->name())); |
| 4020 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3978 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 4021 PrepareForBailout(expr, TOS_REG); | 3979 PrepareForBailout(expr, TOS_REG); |
| 4022 __ bind(&done); | 3980 __ bind(&done); |
| 4023 | 3981 |
| 4024 context()->Plug(eax); | 3982 context()->Plug(eax); |
| 4025 } else { | 3983 } else { |
| 4026 // This expression cannot throw a reference error at the top level. | 3984 // This expression cannot throw a reference error at the top level. |
| 4027 context()->HandleExpression(expr); | 3985 VisitInCurrentContext(expr); |
| 4028 } | 3986 } |
| 4029 } | 3987 } |
| 4030 | 3988 |
| 4031 | 3989 |
| 4032 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, | 3990 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, |
| 4033 Expression* left, | 3991 Handle<String> check, |
| 4034 Expression* right, | 3992 Label* if_true, |
| 4035 Label* if_true, | 3993 Label* if_false, |
| 4036 Label* if_false, | 3994 Label* fall_through) { |
| 4037 Label* fall_through) { | |
| 4038 if (op != Token::EQ && op != Token::EQ_STRICT) return false; | |
| 4039 | |
| 4040 // Check for the pattern: typeof <expression> == <string literal>. | |
| 4041 Literal* right_literal = right->AsLiteral(); | |
| 4042 if (right_literal == NULL) return false; | |
| 4043 Handle<Object> right_literal_value = right_literal->handle(); | |
| 4044 if (!right_literal_value->IsString()) return false; | |
| 4045 UnaryOperation* left_unary = left->AsUnaryOperation(); | |
| 4046 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | |
| 4047 Handle<String> check = Handle<String>::cast(right_literal_value); | |
| 4048 | |
| 4049 { AccumulatorValueContext context(this); | 3995 { AccumulatorValueContext context(this); |
| 4050 VisitForTypeofValue(left_unary->expression()); | 3996 VisitForTypeofValue(expr); |
| 4051 } | 3997 } |
| 4052 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3998 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4053 | 3999 |
| 4054 if (check->Equals(isolate()->heap()->number_symbol())) { | 4000 if (check->Equals(isolate()->heap()->number_symbol())) { |
| 4055 __ JumpIfSmi(eax, if_true); | 4001 __ JumpIfSmi(eax, if_true); |
| 4056 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 4002 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 4057 isolate()->factory()->heap_number_map()); | 4003 isolate()->factory()->heap_number_map()); |
| 4058 Split(equal, if_true, if_false, fall_through); | 4004 Split(equal, if_true, if_false, fall_through); |
| 4059 } else if (check->Equals(isolate()->heap()->string_symbol())) { | 4005 } else if (check->Equals(isolate()->heap()->string_symbol())) { |
| 4060 __ JumpIfSmi(eax, if_false); | 4006 __ JumpIfSmi(eax, if_false); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 4073 __ cmp(eax, isolate()->factory()->undefined_value()); | 4019 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 4074 __ j(equal, if_true); | 4020 __ j(equal, if_true); |
| 4075 __ JumpIfSmi(eax, if_false); | 4021 __ JumpIfSmi(eax, if_false); |
| 4076 // Check for undetectable objects => true. | 4022 // Check for undetectable objects => true. |
| 4077 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 4023 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 4078 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); | 4024 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 4079 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); | 4025 __ test(ecx, Immediate(1 << Map::kIsUndetectable)); |
| 4080 Split(not_zero, if_true, if_false, fall_through); | 4026 Split(not_zero, if_true, if_false, fall_through); |
| 4081 } else if (check->Equals(isolate()->heap()->function_symbol())) { | 4027 } else if (check->Equals(isolate()->heap()->function_symbol())) { |
| 4082 __ JumpIfSmi(eax, if_false); | 4028 __ JumpIfSmi(eax, if_false); |
| 4083 __ CmpObjectType(eax, FIRST_FUNCTION_CLASS_TYPE, edx); | 4029 __ CmpObjectType(eax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, edx); |
| 4084 Split(above_equal, if_true, if_false, fall_through); | 4030 Split(above_equal, if_true, if_false, fall_through); |
| 4085 } else if (check->Equals(isolate()->heap()->object_symbol())) { | 4031 } else if (check->Equals(isolate()->heap()->object_symbol())) { |
| 4086 __ JumpIfSmi(eax, if_false); | 4032 __ JumpIfSmi(eax, if_false); |
| 4087 __ cmp(eax, isolate()->factory()->null_value()); | 4033 __ cmp(eax, isolate()->factory()->null_value()); |
| 4088 __ j(equal, if_true); | 4034 __ j(equal, if_true); |
| 4089 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, edx); | 4035 __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx); |
| 4090 __ j(below, if_false); | 4036 __ j(below, if_false); |
| 4091 __ CmpInstanceType(edx, FIRST_FUNCTION_CLASS_TYPE); | 4037 __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 4092 __ j(above_equal, if_false); | 4038 __ j(above, if_false); |
| 4093 // Check for undetectable objects => false. | 4039 // Check for undetectable objects => false. |
| 4094 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), | 4040 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), |
| 4095 1 << Map::kIsUndetectable); | 4041 1 << Map::kIsUndetectable); |
| 4096 Split(zero, if_true, if_false, fall_through); | 4042 Split(zero, if_true, if_false, fall_through); |
| 4097 } else { | 4043 } else { |
| 4098 if (if_false != fall_through) __ jmp(if_false); | 4044 if (if_false != fall_through) __ jmp(if_false); |
| 4099 } | 4045 } |
| 4100 | |
| 4101 return true; | |
| 4102 } | 4046 } |
| 4103 | 4047 |
| 4104 | 4048 |
| 4049 void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr, |
| 4050 Label* if_true, |
| 4051 Label* if_false, |
| 4052 Label* fall_through) { |
| 4053 VisitForAccumulatorValue(expr); |
| 4054 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4055 |
| 4056 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 4057 Split(equal, if_true, if_false, fall_through); |
| 4058 } |
| 4059 |
| 4060 |
| 4105 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 4061 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| 4106 Comment cmnt(masm_, "[ CompareOperation"); | 4062 Comment cmnt(masm_, "[ CompareOperation"); |
| 4107 SetSourcePosition(expr->position()); | 4063 SetSourcePosition(expr->position()); |
| 4108 | 4064 |
| 4109 // Always perform the comparison for its control flow. Pack the result | 4065 // Always perform the comparison for its control flow. Pack the result |
| 4110 // into the expression's context after the comparison is performed. | 4066 // into the expression's context after the comparison is performed. |
| 4111 | 4067 |
| 4112 Label materialize_true, materialize_false; | 4068 Label materialize_true, materialize_false; |
| 4113 Label* if_true = NULL; | 4069 Label* if_true = NULL; |
| 4114 Label* if_false = NULL; | 4070 Label* if_false = NULL; |
| 4115 Label* fall_through = NULL; | 4071 Label* fall_through = NULL; |
| 4116 context()->PrepareTest(&materialize_true, &materialize_false, | 4072 context()->PrepareTest(&materialize_true, &materialize_false, |
| 4117 &if_true, &if_false, &fall_through); | 4073 &if_true, &if_false, &fall_through); |
| 4118 | 4074 |
| 4119 // First we try a fast inlined version of the compare when one of | 4075 // First we try a fast inlined version of the compare when one of |
| 4120 // the operands is a literal. | 4076 // the operands is a literal. |
| 4121 Token::Value op = expr->op(); | 4077 if (TryLiteralCompare(expr, if_true, if_false, fall_through)) { |
| 4122 Expression* left = expr->left(); | |
| 4123 Expression* right = expr->right(); | |
| 4124 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { | |
| 4125 context()->Plug(if_true, if_false); | 4078 context()->Plug(if_true, if_false); |
| 4126 return; | 4079 return; |
| 4127 } | 4080 } |
| 4128 | 4081 |
| 4082 Token::Value op = expr->op(); |
| 4129 VisitForStackValue(expr->left()); | 4083 VisitForStackValue(expr->left()); |
| 4130 switch (expr->op()) { | 4084 switch (expr->op()) { |
| 4131 case Token::IN: | 4085 case Token::IN: |
| 4132 VisitForStackValue(expr->right()); | 4086 VisitForStackValue(expr->right()); |
| 4133 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 4087 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 4134 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 4088 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 4135 __ cmp(eax, isolate()->factory()->true_value()); | 4089 __ cmp(eax, isolate()->factory()->true_value()); |
| 4136 Split(equal, if_true, if_false, fall_through); | 4090 Split(equal, if_true, if_false, fall_through); |
| 4137 break; | 4091 break; |
| 4138 | 4092 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4193 __ or_(ecx, Operand(eax)); | 4147 __ or_(ecx, Operand(eax)); |
| 4194 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); | 4148 patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear); |
| 4195 __ cmp(edx, Operand(eax)); | 4149 __ cmp(edx, Operand(eax)); |
| 4196 Split(cc, if_true, if_false, NULL); | 4150 Split(cc, if_true, if_false, NULL); |
| 4197 __ bind(&slow_case); | 4151 __ bind(&slow_case); |
| 4198 } | 4152 } |
| 4199 | 4153 |
| 4200 // Record position and call the compare IC. | 4154 // Record position and call the compare IC. |
| 4201 SetSourcePosition(expr->position()); | 4155 SetSourcePosition(expr->position()); |
| 4202 Handle<Code> ic = CompareIC::GetUninitialized(op); | 4156 Handle<Code> ic = CompareIC::GetUninitialized(op); |
| 4203 EmitCallIC(ic, &patch_site, expr->id()); | 4157 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 4158 patch_site.EmitPatchInfo(); |
| 4204 | 4159 |
| 4205 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4160 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4206 __ test(eax, Operand(eax)); | 4161 __ test(eax, Operand(eax)); |
| 4207 Split(cc, if_true, if_false, fall_through); | 4162 Split(cc, if_true, if_false, fall_through); |
| 4208 } | 4163 } |
| 4209 } | 4164 } |
| 4210 | 4165 |
| 4211 // Convert the result of the comparison into one expected for this | 4166 // Convert the result of the comparison into one expected for this |
| 4212 // expression's context. | 4167 // expression's context. |
| 4213 context()->Plug(if_true, if_false); | 4168 context()->Plug(if_true, if_false); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 4225 VisitForAccumulatorValue(expr->expression()); | 4180 VisitForAccumulatorValue(expr->expression()); |
| 4226 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4181 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4227 | 4182 |
| 4228 __ cmp(eax, isolate()->factory()->null_value()); | 4183 __ cmp(eax, isolate()->factory()->null_value()); |
| 4229 if (expr->is_strict()) { | 4184 if (expr->is_strict()) { |
| 4230 Split(equal, if_true, if_false, fall_through); | 4185 Split(equal, if_true, if_false, fall_through); |
| 4231 } else { | 4186 } else { |
| 4232 __ j(equal, if_true); | 4187 __ j(equal, if_true); |
| 4233 __ cmp(eax, isolate()->factory()->undefined_value()); | 4188 __ cmp(eax, isolate()->factory()->undefined_value()); |
| 4234 __ j(equal, if_true); | 4189 __ j(equal, if_true); |
| 4235 __ test(eax, Immediate(kSmiTagMask)); | 4190 __ JumpIfSmi(eax, if_false); |
| 4236 __ j(zero, if_false); | |
| 4237 // It can be an undetectable object. | 4191 // It can be an undetectable object. |
| 4238 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 4192 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 4239 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset)); | 4193 __ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset)); |
| 4240 __ test(edx, Immediate(1 << Map::kIsUndetectable)); | 4194 __ test(edx, Immediate(1 << Map::kIsUndetectable)); |
| 4241 Split(not_zero, if_true, if_false, fall_through); | 4195 Split(not_zero, if_true, if_false, fall_through); |
| 4242 } | 4196 } |
| 4243 context()->Plug(if_true, if_false); | 4197 context()->Plug(if_true, if_false); |
| 4244 } | 4198 } |
| 4245 | 4199 |
| 4246 | 4200 |
| 4247 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 4201 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
| 4248 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); | 4202 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4249 context()->Plug(eax); | 4203 context()->Plug(eax); |
| 4250 } | 4204 } |
| 4251 | 4205 |
| 4252 | 4206 |
| 4253 Register FullCodeGenerator::result_register() { | 4207 Register FullCodeGenerator::result_register() { |
| 4254 return eax; | 4208 return eax; |
| 4255 } | 4209 } |
| 4256 | 4210 |
| 4257 | 4211 |
| 4258 Register FullCodeGenerator::context_register() { | 4212 Register FullCodeGenerator::context_register() { |
| 4259 return esi; | 4213 return esi; |
| 4260 } | 4214 } |
| 4261 | 4215 |
| 4262 | 4216 |
| 4263 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, | |
| 4264 RelocInfo::Mode mode, | |
| 4265 unsigned ast_id) { | |
| 4266 ASSERT(mode == RelocInfo::CODE_TARGET || | |
| 4267 mode == RelocInfo::CODE_TARGET_CONTEXT); | |
| 4268 switch (ic->kind()) { | |
| 4269 case Code::LOAD_IC: | |
| 4270 __ IncrementCounter(isolate()->counters()->named_load_full(), 1); | |
| 4271 break; | |
| 4272 case Code::KEYED_LOAD_IC: | |
| 4273 __ IncrementCounter(isolate()->counters()->keyed_load_full(), 1); | |
| 4274 break; | |
| 4275 case Code::STORE_IC: | |
| 4276 __ IncrementCounter(isolate()->counters()->named_store_full(), 1); | |
| 4277 break; | |
| 4278 case Code::KEYED_STORE_IC: | |
| 4279 __ IncrementCounter(isolate()->counters()->keyed_store_full(), 1); | |
| 4280 default: | |
| 4281 break; | |
| 4282 } | |
| 4283 __ call(ic, mode, ast_id); | |
| 4284 } | |
| 4285 | |
| 4286 | |
| 4287 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, | |
| 4288 JumpPatchSite* patch_site, | |
| 4289 unsigned ast_id) { | |
| 4290 Counters* counters = isolate()->counters(); | |
| 4291 switch (ic->kind()) { | |
| 4292 case Code::LOAD_IC: | |
| 4293 __ IncrementCounter(counters->named_load_full(), 1); | |
| 4294 break; | |
| 4295 case Code::KEYED_LOAD_IC: | |
| 4296 __ IncrementCounter(counters->keyed_load_full(), 1); | |
| 4297 break; | |
| 4298 case Code::STORE_IC: | |
| 4299 __ IncrementCounter(counters->named_store_full(), 1); | |
| 4300 break; | |
| 4301 case Code::KEYED_STORE_IC: | |
| 4302 __ IncrementCounter(counters->keyed_store_full(), 1); | |
| 4303 default: | |
| 4304 break; | |
| 4305 } | |
| 4306 __ call(ic, RelocInfo::CODE_TARGET, ast_id); | |
| 4307 if (patch_site != NULL && patch_site->is_bound()) { | |
| 4308 patch_site->EmitPatchInfo(); | |
| 4309 } else { | |
| 4310 __ nop(); // Signals no inlined code. | |
| 4311 } | |
| 4312 } | |
| 4313 | |
| 4314 | |
| 4315 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 4217 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
| 4316 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); | 4218 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); |
| 4317 __ mov(Operand(ebp, frame_offset), value); | 4219 __ mov(Operand(ebp, frame_offset), value); |
| 4318 } | 4220 } |
| 4319 | 4221 |
| 4320 | 4222 |
| 4321 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { | 4223 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { |
| 4322 __ mov(dst, ContextOperand(esi, context_index)); | 4224 __ mov(dst, ContextOperand(esi, context_index)); |
| 4323 } | 4225 } |
| 4324 | 4226 |
| 4325 | 4227 |
| 4228 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { |
| 4229 Scope* declaration_scope = scope()->DeclarationScope(); |
| 4230 if (declaration_scope->is_global_scope()) { |
| 4231 // Contexts nested in the global context have a canonical empty function |
| 4232 // as their closure, not the anonymous closure containing the global |
| 4233 // code. Pass a smi sentinel and let the runtime look up the empty |
| 4234 // function. |
| 4235 __ push(Immediate(Smi::FromInt(0))); |
| 4236 } else if (declaration_scope->is_eval_scope()) { |
| 4237 // Contexts nested inside eval code have the same closure as the context |
| 4238 // calling eval, not the anonymous closure containing the eval code. |
| 4239 // Fetch it from the context. |
| 4240 __ push(ContextOperand(esi, Context::CLOSURE_INDEX)); |
| 4241 } else { |
| 4242 ASSERT(declaration_scope->is_function_scope()); |
| 4243 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4244 } |
| 4245 } |
| 4246 |
| 4247 |
| 4326 // ---------------------------------------------------------------------------- | 4248 // ---------------------------------------------------------------------------- |
| 4327 // Non-local control flow support. | 4249 // Non-local control flow support. |
| 4328 | 4250 |
| 4329 void FullCodeGenerator::EnterFinallyBlock() { | 4251 void FullCodeGenerator::EnterFinallyBlock() { |
| 4330 // Cook return address on top of stack (smi encoded Code* delta) | 4252 // Cook return address on top of stack (smi encoded Code* delta) |
| 4331 ASSERT(!result_register().is(edx)); | 4253 ASSERT(!result_register().is(edx)); |
| 4332 __ mov(edx, Operand(esp, 0)); | 4254 __ pop(edx); |
| 4333 __ sub(Operand(edx), Immediate(masm_->CodeObject())); | 4255 __ sub(Operand(edx), Immediate(masm_->CodeObject())); |
| 4334 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 4256 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); |
| 4335 ASSERT_EQ(0, kSmiTag); | 4257 ASSERT_EQ(0, kSmiTag); |
| 4336 __ add(edx, Operand(edx)); // Convert to smi. | 4258 __ SmiTag(edx); |
| 4337 __ mov(Operand(esp, 0), edx); | 4259 __ push(edx); |
| 4338 // Store result register while executing finally block. | 4260 // Store result register while executing finally block. |
| 4339 __ push(result_register()); | 4261 __ push(result_register()); |
| 4340 } | 4262 } |
| 4341 | 4263 |
| 4342 | 4264 |
| 4343 void FullCodeGenerator::ExitFinallyBlock() { | 4265 void FullCodeGenerator::ExitFinallyBlock() { |
| 4344 ASSERT(!result_register().is(edx)); | 4266 ASSERT(!result_register().is(edx)); |
| 4345 // Restore result register from stack. | |
| 4346 __ pop(result_register()); | 4267 __ pop(result_register()); |
| 4347 // Uncook return address. | 4268 // Uncook return address. |
| 4348 __ mov(edx, Operand(esp, 0)); | 4269 __ pop(edx); |
| 4349 __ sar(edx, 1); // Convert smi to int. | 4270 __ SmiUntag(edx); |
| 4350 __ add(Operand(edx), Immediate(masm_->CodeObject())); | 4271 __ add(Operand(edx), Immediate(masm_->CodeObject())); |
| 4351 __ mov(Operand(esp, 0), edx); | 4272 __ jmp(Operand(edx)); |
| 4352 // And return. | |
| 4353 __ ret(0); | |
| 4354 } | 4273 } |
| 4355 | 4274 |
| 4356 | 4275 |
| 4357 #undef __ | 4276 #undef __ |
| 4358 | 4277 |
| 4359 } } // namespace v8::internal | 4278 } } // namespace v8::internal |
| 4360 | 4279 |
| 4361 #endif // V8_TARGET_ARCH_IA32 | 4280 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |