| 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 near_jump = Label::kFar) { | 75 Label::Distance near_jump = Label::kFar) { |
| 76 __ testb(reg, Immediate(kSmiTagMask)); | 76 __ testb(reg, Immediate(kSmiTagMask)); |
| 77 EmitJump(carry, target, near_jump); // Never taken before patched. | 77 EmitJump(carry, target, near_jump); // 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 __ testl(rax, Immediate(delta_to_patch_site)); | 83 ASSERT(is_int8(delta_to_patch_site)); |
| 84 __ testl(rax, 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 near_jump) { | 95 void EmitJump(Condition cc, Label* target, Label::Distance near_jump) { |
| 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, near_jump); | 99 __ j(cc, target, near_jump); |
| 98 } | 100 } |
| 99 | 101 |
| 100 MacroAssembler* masm_; | 102 MacroAssembler* masm_; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 114 // o rdi: the JS function object being called (ie, ourselves) | 116 // o rdi: the JS function object being called (ie, ourselves) |
| 115 // o rsi: our context | 117 // o rsi: our context |
| 116 // o rbp: our caller's frame pointer | 118 // o rbp: our caller's frame pointer |
| 117 // o rsp: stack pointer (pointing to return address) | 119 // o rsp: 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-x64.h for its layout. | 122 // frames-x64.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). rcx is zero for method calls and non-zero for function | 139 // receiver object). rcx 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 __ testq(rcx, rcx); | 143 __ testq(rcx, rcx); |
| 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 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); | 147 __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); |
| 145 __ movq(Operand(rsp, receiver_offset), kScratchRegister); | 148 __ movq(Operand(rsp, receiver_offset), kScratchRegister); |
| 146 __ bind(&ok); | 149 __ bind(&ok); |
| 147 } | 150 } |
| 148 | 151 |
| 149 __ push(rbp); // Caller's frame pointer. | 152 __ push(rbp); // Caller's frame pointer. |
| 150 __ movq(rbp, rsp); | 153 __ movq(rbp, rsp); |
| 151 __ push(rsi); // Callee's context. | 154 __ push(rsi); // Callee's context. |
| 152 __ push(rdi); // Callee's JS Function. | 155 __ push(rdi); // 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 __ PushRoot(Heap::kUndefinedValueRootIndex); | 160 __ PushRoot(Heap::kUndefinedValueRootIndex); |
| 158 } else if (locals_count > 1) { | 161 } else if (locals_count > 1) { |
| 159 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); | 162 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); |
| 160 for (int i = 0; i < locals_count; i++) { | 163 for (int i = 0; i < locals_count; i++) { |
| 161 __ push(rdx); | 164 __ push(rdx); |
| 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 rdi. | 175 // Argument to NewContext is the function, which is still in rdi. |
| 173 __ push(rdi); | 176 __ push(rdi); |
| 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 rax and rsi. It replaces the context | 184 // Context is returned in both rax and rsi. It replaces the context |
| 182 // passed to us. It's saved in the stack and kept live in rsi. | 185 // passed to us. It's saved in the stack and kept live in rsi. |
| 183 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); | 186 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); |
| 184 | 187 |
| 185 // Copy any necessary parameters into the context. | 188 // Copy any necessary parameters into the context. |
| 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 __ movq(rax, Operand(rbp, parameter_offset)); | 196 __ movq(rax, Operand(rbp, 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 __ movq(Operand(rsi, context_offset), rax); | 199 __ movq(Operand(rsi, context_offset), rax); |
| 197 // Update the write barrier. This clobbers rax and rbx. | 200 // Update the write barrier. This clobbers rax and rbx. |
| 198 __ RecordWriteContextSlot( | 201 __ RecordWriteContextSlot( |
| 199 rsi, context_offset, rax, rbx, kDontSaveFPRegs); | 202 rsi, context_offset, rax, rbx, kDontSaveFPRegs); |
| 200 } | 203 } |
| 201 } | 204 } |
| 202 } | 205 } |
| 203 | 206 |
| 204 // Possibly allocate an arguments object. | 207 // Possibly allocate an arguments object. |
| 205 Variable* arguments = scope()->arguments(); | 208 Variable* arguments = scope()->arguments(); |
| 206 if (arguments != NULL) { | 209 if (arguments != NULL) { |
| 207 // Arguments object must be allocated after the context object, in | 210 // Arguments object must be allocated after the context object, in |
| 208 // case the "arguments" or ".arguments" variables are in the context. | 211 // case the "arguments" or ".arguments" variables are in the context. |
| 209 Comment cmnt(masm_, "[ Allocate arguments object"); | 212 Comment cmnt(masm_, "[ Allocate arguments object"); |
| 210 if (function_in_register) { | 213 if (function_in_register) { |
| 211 __ push(rdi); | 214 __ push(rdi); |
| 212 } else { | 215 } else { |
| 213 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 216 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 214 } | 217 } |
| 215 // The receiver is just before the parameters on the caller's stack. | 218 // The receiver is just before the parameters on the caller's stack. |
| 216 int offset = scope()->num_parameters() * kPointerSize; | 219 int num_parameters = info->scope()->num_parameters(); |
| 220 int offset = num_parameters * kPointerSize; |
| 217 __ lea(rdx, | 221 __ lea(rdx, |
| 218 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset)); | 222 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset)); |
| 219 __ push(rdx); | 223 __ push(rdx); |
| 220 __ Push(Smi::FromInt(scope()->num_parameters())); | 224 __ Push(Smi::FromInt(num_parameters)); |
| 221 // Arguments to ArgumentsAccessStub: | 225 // Arguments to ArgumentsAccessStub: |
| 222 // function, receiver address, parameter count. | 226 // function, receiver address, parameter count. |
| 223 // The stub will rewrite receiver and parameter count if the previous | 227 // The stub will rewrite receiver and parameter count if the previous |
| 224 // stack frame was an arguments adapter frame. | 228 // stack frame was an arguments adapter frame. |
| 225 ArgumentsAccessStub stub( | 229 ArgumentsAccessStub stub( |
| 226 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT | 230 is_strict_mode() ? ArgumentsAccessStub::NEW_STRICT |
| 227 : ArgumentsAccessStub::NEW_NON_STRICT); | 231 : ArgumentsAccessStub::NEW_NON_STRICT_SLOW); |
| 228 __ CallStub(&stub); | 232 __ CallStub(&stub); |
| 229 | 233 |
| 230 Variable* arguments_shadow = scope()->arguments_shadow(); | |
| 231 if (arguments_shadow != NULL) { | |
| 232 // Store new arguments object in both "arguments" and ".arguments" slots. | |
| 233 __ movq(rcx, rax); | |
| 234 Move(arguments_shadow->AsSlot(), rcx, rbx, rdx); | |
| 235 } | |
| 236 Move(arguments->AsSlot(), rax, rbx, rdx); | 234 Move(arguments->AsSlot(), rax, rbx, rdx); |
| 237 } | 235 } |
| 238 | 236 |
| 239 if (FLAG_trace) { | 237 if (FLAG_trace) { |
| 240 __ CallRuntime(Runtime::kTraceEnter, 0); | 238 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 241 } | 239 } |
| 242 | 240 |
| 243 // Visit the declarations and body unless there is an illegal | 241 // Visit the declarations and body unless there is an illegal |
| 244 // redeclaration. | 242 // redeclaration. |
| 245 if (scope()->HasIllegalRedeclaration()) { | 243 if (scope()->HasIllegalRedeclaration()) { |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 329 Label check_exit_codesize; | 327 Label check_exit_codesize; |
| 330 masm_->bind(&check_exit_codesize); | 328 masm_->bind(&check_exit_codesize); |
| 331 #endif | 329 #endif |
| 332 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); | 330 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1); |
| 333 __ RecordJSReturn(); | 331 __ RecordJSReturn(); |
| 334 // Do not use the leave instruction here because it is too short to | 332 // Do not use the leave instruction here because it is too short to |
| 335 // patch with the code required by the debugger. | 333 // patch with the code required by the debugger. |
| 336 __ movq(rsp, rbp); | 334 __ movq(rsp, rbp); |
| 337 __ pop(rbp); | 335 __ pop(rbp); |
| 338 | 336 |
| 339 int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize; | 337 int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize; |
| 340 __ Ret(arguments_bytes, rcx); | 338 __ Ret(arguments_bytes, rcx); |
| 341 | 339 |
| 342 #ifdef ENABLE_DEBUGGER_SUPPORT | 340 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 343 // Add padding that will be overwritten by a debugger breakpoint. We | 341 // Add padding that will be overwritten by a debugger breakpoint. We |
| 344 // have just generated at least 7 bytes: "movq rsp, rbp; pop rbp; ret k" | 342 // have just generated at least 7 bytes: "movq rsp, rbp; pop rbp; ret k" |
| 345 // (3 + 1 + 3). | 343 // (3 + 1 + 3). |
| 346 const int kPadding = Assembler::kJSReturnSequenceLength - 7; | 344 const int kPadding = Assembler::kJSReturnSequenceLength - 7; |
| 347 for (int i = 0; i < kPadding; ++i) { | 345 for (int i = 0; i < kPadding; ++i) { |
| 348 masm_->int3(); | 346 masm_->int3(); |
| 349 } | 347 } |
| (...skipping 18 matching lines...) Expand all Loading... |
| 368 | 366 |
| 369 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { | 367 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { |
| 370 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); | 368 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); |
| 371 __ push(slot_operand); | 369 __ push(slot_operand); |
| 372 } | 370 } |
| 373 | 371 |
| 374 | 372 |
| 375 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { | 373 void FullCodeGenerator::TestContext::Plug(Slot* slot) const { |
| 376 codegen()->Move(result_register(), slot); | 374 codegen()->Move(result_register(), slot); |
| 377 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 375 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 378 codegen()->DoTest(true_label_, false_label_, fall_through_); | 376 codegen()->DoTest(this); |
| 379 } | 377 } |
| 380 | 378 |
| 381 | 379 |
| 382 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { | 380 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const { |
| 383 } | 381 } |
| 384 | 382 |
| 385 | 383 |
| 386 void FullCodeGenerator::AccumulatorValueContext::Plug( | 384 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 387 Heap::RootListIndex index) const { | 385 Heap::RootListIndex index) const { |
| 388 __ LoadRoot(result_register(), index); | 386 __ LoadRoot(result_register(), index); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 401 true_label_, | 399 true_label_, |
| 402 false_label_); | 400 false_label_); |
| 403 if (index == Heap::kUndefinedValueRootIndex || | 401 if (index == Heap::kUndefinedValueRootIndex || |
| 404 index == Heap::kNullValueRootIndex || | 402 index == Heap::kNullValueRootIndex || |
| 405 index == Heap::kFalseValueRootIndex) { | 403 index == Heap::kFalseValueRootIndex) { |
| 406 if (false_label_ != fall_through_) __ jmp(false_label_); | 404 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 407 } else if (index == Heap::kTrueValueRootIndex) { | 405 } else if (index == Heap::kTrueValueRootIndex) { |
| 408 if (true_label_ != fall_through_) __ jmp(true_label_); | 406 if (true_label_ != fall_through_) __ jmp(true_label_); |
| 409 } else { | 407 } else { |
| 410 __ LoadRoot(result_register(), index); | 408 __ LoadRoot(result_register(), index); |
| 411 codegen()->DoTest(true_label_, false_label_, fall_through_); | 409 codegen()->DoTest(this); |
| 412 } | 410 } |
| 413 } | 411 } |
| 414 | 412 |
| 415 | 413 |
| 416 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { | 414 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const { |
| 417 } | 415 } |
| 418 | 416 |
| 419 | 417 |
| 420 void FullCodeGenerator::AccumulatorValueContext::Plug( | 418 void FullCodeGenerator::AccumulatorValueContext::Plug( |
| 421 Handle<Object> lit) const { | 419 Handle<Object> lit) const { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 446 } | 444 } |
| 447 } else if (lit->IsSmi()) { | 445 } else if (lit->IsSmi()) { |
| 448 if (Smi::cast(*lit)->value() == 0) { | 446 if (Smi::cast(*lit)->value() == 0) { |
| 449 if (false_label_ != fall_through_) __ jmp(false_label_); | 447 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 450 } else { | 448 } else { |
| 451 if (true_label_ != fall_through_) __ jmp(true_label_); | 449 if (true_label_ != fall_through_) __ jmp(true_label_); |
| 452 } | 450 } |
| 453 } else { | 451 } else { |
| 454 // For simplicity we always test the accumulator register. | 452 // For simplicity we always test the accumulator register. |
| 455 __ Move(result_register(), lit); | 453 __ Move(result_register(), lit); |
| 456 codegen()->DoTest(true_label_, false_label_, fall_through_); | 454 codegen()->DoTest(this); |
| 457 } | 455 } |
| 458 } | 456 } |
| 459 | 457 |
| 460 | 458 |
| 461 void FullCodeGenerator::EffectContext::DropAndPlug(int count, | 459 void FullCodeGenerator::EffectContext::DropAndPlug(int count, |
| 462 Register reg) const { | 460 Register reg) const { |
| 463 ASSERT(count > 0); | 461 ASSERT(count > 0); |
| 464 __ Drop(count); | 462 __ Drop(count); |
| 465 } | 463 } |
| 466 | 464 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 482 } | 480 } |
| 483 | 481 |
| 484 | 482 |
| 485 void FullCodeGenerator::TestContext::DropAndPlug(int count, | 483 void FullCodeGenerator::TestContext::DropAndPlug(int count, |
| 486 Register reg) const { | 484 Register reg) const { |
| 487 ASSERT(count > 0); | 485 ASSERT(count > 0); |
| 488 // For simplicity we always test the accumulator register. | 486 // For simplicity we always test the accumulator register. |
| 489 __ Drop(count); | 487 __ Drop(count); |
| 490 __ Move(result_register(), reg); | 488 __ Move(result_register(), reg); |
| 491 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 489 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 492 codegen()->DoTest(true_label_, false_label_, fall_through_); | 490 codegen()->DoTest(this); |
| 493 } | 491 } |
| 494 | 492 |
| 495 | 493 |
| 496 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, | 494 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true, |
| 497 Label* materialize_false) const { | 495 Label* materialize_false) const { |
| 498 ASSERT(materialize_true == materialize_false); | 496 ASSERT(materialize_true == materialize_false); |
| 499 __ bind(materialize_true); | 497 __ bind(materialize_true); |
| 500 } | 498 } |
| 501 | 499 |
| 502 | 500 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 true_label_, | 555 true_label_, |
| 558 false_label_); | 556 false_label_); |
| 559 if (flag) { | 557 if (flag) { |
| 560 if (true_label_ != fall_through_) __ jmp(true_label_); | 558 if (true_label_ != fall_through_) __ jmp(true_label_); |
| 561 } else { | 559 } else { |
| 562 if (false_label_ != fall_through_) __ jmp(false_label_); | 560 if (false_label_ != fall_through_) __ jmp(false_label_); |
| 563 } | 561 } |
| 564 } | 562 } |
| 565 | 563 |
| 566 | 564 |
| 567 void FullCodeGenerator::DoTest(Label* if_true, | 565 void FullCodeGenerator::DoTest(Expression* condition, |
| 566 Label* if_true, |
| 568 Label* if_false, | 567 Label* if_false, |
| 569 Label* fall_through) { | 568 Label* fall_through) { |
| 570 ToBooleanStub stub; | 569 ToBooleanStub stub(result_register()); |
| 571 __ push(result_register()); | 570 __ push(result_register()); |
| 572 __ CallStub(&stub); | 571 __ CallStub(&stub); |
| 573 __ testq(rax, rax); | 572 __ testq(result_register(), result_register()); |
| 574 // The stub returns nonzero for true. | 573 // The stub returns nonzero for true. |
| 575 Split(not_zero, if_true, if_false, fall_through); | 574 Split(not_zero, if_true, if_false, fall_through); |
| 576 } | 575 } |
| 577 | 576 |
| 578 | 577 |
| 579 void FullCodeGenerator::Split(Condition cc, | 578 void FullCodeGenerator::Split(Condition cc, |
| 580 Label* if_true, | 579 Label* if_true, |
| 581 Label* if_false, | 580 Label* if_false, |
| 582 Label* fall_through) { | 581 Label* fall_through) { |
| 583 if (if_false == fall_through) { | 582 if (if_false == fall_through) { |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 677 } else if (function != NULL) { | 676 } else if (function != NULL) { |
| 678 VisitForAccumulatorValue(function); | 677 VisitForAccumulatorValue(function); |
| 679 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); | 678 __ movq(Operand(rbp, SlotOffset(slot)), result_register()); |
| 680 } | 679 } |
| 681 break; | 680 break; |
| 682 | 681 |
| 683 case Slot::CONTEXT: | 682 case Slot::CONTEXT: |
| 684 // We bypass the general EmitSlotSearch because we know more about | 683 // We bypass the general EmitSlotSearch because we know more about |
| 685 // this specific context. | 684 // this specific context. |
| 686 | 685 |
| 687 // The variable in the decl always resides in the current context. | 686 // The variable in the decl always resides in the current function |
| 687 // context. |
| 688 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 688 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
| 689 if (FLAG_debug_code) { | 689 if (FLAG_debug_code) { |
| 690 // Check if we have the correct context pointer. | 690 // Check that we're not inside a with or catch context. |
| 691 __ movq(rbx, ContextOperand(rsi, Context::FCONTEXT_INDEX)); | 691 __ movq(rbx, FieldOperand(rsi, HeapObject::kMapOffset)); |
| 692 __ cmpq(rbx, rsi); | 692 __ CompareRoot(rbx, Heap::kWithContextMapRootIndex); |
| 693 __ Check(equal, "Unexpected declaration in current context."); | 693 __ Check(not_equal, "Declaration in with context."); |
| 694 __ CompareRoot(rbx, Heap::kCatchContextMapRootIndex); |
| 695 __ Check(not_equal, "Declaration in catch context."); |
| 694 } | 696 } |
| 695 if (mode == Variable::CONST) { | 697 if (mode == Variable::CONST) { |
| 696 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); | 698 __ LoadRoot(kScratchRegister, Heap::kTheHoleValueRootIndex); |
| 697 __ movq(ContextOperand(rsi, slot->index()), kScratchRegister); | 699 __ movq(ContextOperand(rsi, slot->index()), kScratchRegister); |
| 698 // No write barrier since the hole value is in old space. | 700 // No write barrier since the hole value is in old space. |
| 699 } else if (function != NULL) { | 701 } else if (function != NULL) { |
| 700 VisitForAccumulatorValue(function); | 702 VisitForAccumulatorValue(function); |
| 701 __ movq(ContextOperand(rsi, slot->index()), result_register()); | 703 __ movq(ContextOperand(rsi, slot->index()), result_register()); |
| 702 int offset = Context::SlotOffset(slot->index()); | 704 int offset = Context::SlotOffset(slot->index()); |
| 703 // We know that we have written a function, which is not a smi. | 705 // We know that we have written a function, which is not a smi. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 __ push(rax); | 751 __ push(rax); |
| 750 VisitForAccumulatorValue(function); | 752 VisitForAccumulatorValue(function); |
| 751 __ pop(rdx); | 753 __ pop(rdx); |
| 752 ASSERT(prop->key()->AsLiteral() != NULL && | 754 ASSERT(prop->key()->AsLiteral() != NULL && |
| 753 prop->key()->AsLiteral()->handle()->IsSmi()); | 755 prop->key()->AsLiteral()->handle()->IsSmi()); |
| 754 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 756 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 755 | 757 |
| 756 Handle<Code> ic = is_strict_mode() | 758 Handle<Code> ic = is_strict_mode() |
| 757 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 759 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 758 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 760 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 759 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 761 __ call(ic); |
| 760 } | 762 } |
| 761 } | 763 } |
| 762 } | 764 } |
| 763 | 765 |
| 764 | 766 |
| 765 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 767 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 766 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 768 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 767 } | 769 } |
| 768 | 770 |
| 769 | 771 |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 822 __ cmpq(rdx, rax); | 824 __ cmpq(rdx, rax); |
| 823 __ j(not_equal, &next_test); | 825 __ j(not_equal, &next_test); |
| 824 __ Drop(1); // Switch value is no longer needed. | 826 __ Drop(1); // Switch value is no longer needed. |
| 825 __ jmp(clause->body_target()); | 827 __ jmp(clause->body_target()); |
| 826 __ bind(&slow_case); | 828 __ bind(&slow_case); |
| 827 } | 829 } |
| 828 | 830 |
| 829 // Record position before stub call for type feedback. | 831 // Record position before stub call for type feedback. |
| 830 SetSourcePosition(clause->position()); | 832 SetSourcePosition(clause->position()); |
| 831 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); | 833 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT); |
| 832 EmitCallIC(ic, &patch_site, clause->CompareId()); | 834 __ call(ic, RelocInfo::CODE_TARGET, clause->CompareId()); |
| 835 patch_site.EmitPatchInfo(); |
| 833 | 836 |
| 834 __ testq(rax, rax); | 837 __ testq(rax, rax); |
| 835 __ j(not_equal, &next_test); | 838 __ j(not_equal, &next_test); |
| 836 __ Drop(1); // Switch value is no longer needed. | 839 __ Drop(1); // Switch value is no longer needed. |
| 837 __ jmp(clause->body_target()); | 840 __ jmp(clause->body_target()); |
| 838 } | 841 } |
| 839 | 842 |
| 840 // Discard the test value and jump to the default if present, otherwise to | 843 // Discard the test value and jump to the default if present, otherwise to |
| 841 // the end of the statement. | 844 // the end of the statement. |
| 842 __ bind(&next_test); | 845 __ bind(&next_test); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 876 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 879 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 877 __ j(equal, &exit); | 880 __ j(equal, &exit); |
| 878 Register null_value = rdi; | 881 Register null_value = rdi; |
| 879 __ LoadRoot(null_value, Heap::kNullValueRootIndex); | 882 __ LoadRoot(null_value, Heap::kNullValueRootIndex); |
| 880 __ cmpq(rax, null_value); | 883 __ cmpq(rax, null_value); |
| 881 __ j(equal, &exit); | 884 __ j(equal, &exit); |
| 882 | 885 |
| 883 // Convert the object to a JS object. | 886 // Convert the object to a JS object. |
| 884 Label convert, done_convert; | 887 Label convert, done_convert; |
| 885 __ JumpIfSmi(rax, &convert); | 888 __ JumpIfSmi(rax, &convert); |
| 886 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); | 889 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); |
| 887 __ j(above_equal, &done_convert); | 890 __ j(above_equal, &done_convert); |
| 888 __ bind(&convert); | 891 __ bind(&convert); |
| 889 __ push(rax); | 892 __ push(rax); |
| 890 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 893 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 891 __ bind(&done_convert); | 894 __ bind(&done_convert); |
| 892 __ push(rax); | 895 __ push(rax); |
| 893 | 896 |
| 894 // Check cache validity in generated code. This is a fast case for | 897 // Check cache validity in generated code. This is a fast case for |
| 895 // the JSObject::IsSimpleEnum cache validity checks. If we cannot | 898 // the JSObject::IsSimpleEnum cache validity checks. If we cannot |
| 896 // guarantee cache validity, call the runtime system to check cache | 899 // guarantee cache validity, call the runtime system to check cache |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1087 Scope* s = scope(); | 1090 Scope* s = scope(); |
| 1088 while (s != NULL) { | 1091 while (s != NULL) { |
| 1089 if (s->num_heap_slots() > 0) { | 1092 if (s->num_heap_slots() > 0) { |
| 1090 if (s->calls_eval()) { | 1093 if (s->calls_eval()) { |
| 1091 // Check that extension is NULL. | 1094 // Check that extension is NULL. |
| 1092 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), | 1095 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), |
| 1093 Immediate(0)); | 1096 Immediate(0)); |
| 1094 __ j(not_equal, slow); | 1097 __ j(not_equal, slow); |
| 1095 } | 1098 } |
| 1096 // Load next context in chain. | 1099 // Load next context in chain. |
| 1097 __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX)); | 1100 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); |
| 1098 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); | |
| 1099 // Walk the rest of the chain without clobbering rsi. | 1101 // Walk the rest of the chain without clobbering rsi. |
| 1100 context = temp; | 1102 context = temp; |
| 1101 } | 1103 } |
| 1102 // If no outer scope calls eval, we do not need to check more | 1104 // If no outer scope calls eval, we do not need to check more |
| 1103 // context extensions. If we have reached an eval scope, we check | 1105 // context extensions. If we have reached an eval scope, we check |
| 1104 // all extensions from this point. | 1106 // all extensions from this point. |
| 1105 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; | 1107 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break; |
| 1106 s = s->outer_scope(); | 1108 s = s->outer_scope(); |
| 1107 } | 1109 } |
| 1108 | 1110 |
| 1109 if (s != NULL && s->is_eval_scope()) { | 1111 if (s != NULL && s->is_eval_scope()) { |
| 1110 // Loop up the context chain. There is no frame effect so it is | 1112 // Loop up the context chain. There is no frame effect so it is |
| 1111 // safe to use raw labels here. | 1113 // safe to use raw labels here. |
| 1112 Label next, fast; | 1114 Label next, fast; |
| 1113 if (!context.is(temp)) { | 1115 if (!context.is(temp)) { |
| 1114 __ movq(temp, context); | 1116 __ movq(temp, context); |
| 1115 } | 1117 } |
| 1116 // Load map for comparison into register, outside loop. | 1118 // Load map for comparison into register, outside loop. |
| 1117 __ LoadRoot(kScratchRegister, Heap::kGlobalContextMapRootIndex); | 1119 __ LoadRoot(kScratchRegister, Heap::kGlobalContextMapRootIndex); |
| 1118 __ bind(&next); | 1120 __ bind(&next); |
| 1119 // Terminate at global context. | 1121 // Terminate at global context. |
| 1120 __ cmpq(kScratchRegister, FieldOperand(temp, HeapObject::kMapOffset)); | 1122 __ cmpq(kScratchRegister, FieldOperand(temp, HeapObject::kMapOffset)); |
| 1121 __ j(equal, &fast, Label::kNear); | 1123 __ j(equal, &fast, Label::kNear); |
| 1122 // Check that extension is NULL. | 1124 // Check that extension is NULL. |
| 1123 __ cmpq(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); | 1125 __ cmpq(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0)); |
| 1124 __ j(not_equal, slow); | 1126 __ j(not_equal, slow); |
| 1125 // Load next context in chain. | 1127 // Load next context in chain. |
| 1126 __ movq(temp, ContextOperand(temp, Context::CLOSURE_INDEX)); | 1128 __ movq(temp, ContextOperand(temp, Context::PREVIOUS_INDEX)); |
| 1127 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); | |
| 1128 __ jmp(&next); | 1129 __ jmp(&next); |
| 1129 __ bind(&fast); | 1130 __ bind(&fast); |
| 1130 } | 1131 } |
| 1131 | 1132 |
| 1132 // All extension objects were empty and it is safe to use a global | 1133 // All extension objects were empty and it is safe to use a global |
| 1133 // load IC call. | 1134 // load IC call. |
| 1134 __ movq(rax, GlobalObjectOperand()); | 1135 __ movq(rax, GlobalObjectOperand()); |
| 1135 __ Move(rcx, slot->var()->name()); | 1136 __ Move(rcx, slot->var()->name()); |
| 1136 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1137 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 1137 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) | 1138 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) |
| 1138 ? RelocInfo::CODE_TARGET | 1139 ? RelocInfo::CODE_TARGET |
| 1139 : RelocInfo::CODE_TARGET_CONTEXT; | 1140 : RelocInfo::CODE_TARGET_CONTEXT; |
| 1140 EmitCallIC(ic, mode, AstNode::kNoNumber); | 1141 __ call(ic, mode); |
| 1141 } | 1142 } |
| 1142 | 1143 |
| 1143 | 1144 |
| 1144 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( | 1145 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( |
| 1145 Slot* slot, | 1146 Slot* slot, |
| 1146 Label* slow) { | 1147 Label* slow) { |
| 1147 ASSERT(slot->type() == Slot::CONTEXT); | 1148 ASSERT(slot->type() == Slot::CONTEXT); |
| 1148 Register context = rsi; | 1149 Register context = rsi; |
| 1149 Register temp = rbx; | 1150 Register temp = rbx; |
| 1150 | 1151 |
| 1151 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { | 1152 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { |
| 1152 if (s->num_heap_slots() > 0) { | 1153 if (s->num_heap_slots() > 0) { |
| 1153 if (s->calls_eval()) { | 1154 if (s->calls_eval()) { |
| 1154 // Check that extension is NULL. | 1155 // Check that extension is NULL. |
| 1155 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), | 1156 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), |
| 1156 Immediate(0)); | 1157 Immediate(0)); |
| 1157 __ j(not_equal, slow); | 1158 __ j(not_equal, slow); |
| 1158 } | 1159 } |
| 1159 __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX)); | 1160 __ movq(temp, ContextOperand(context, Context::PREVIOUS_INDEX)); |
| 1160 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); | |
| 1161 // Walk the rest of the chain without clobbering rsi. | 1161 // Walk the rest of the chain without clobbering rsi. |
| 1162 context = temp; | 1162 context = temp; |
| 1163 } | 1163 } |
| 1164 } | 1164 } |
| 1165 // Check that last extension is NULL. | 1165 // Check that last extension is NULL. |
| 1166 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); | 1166 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); |
| 1167 __ j(not_equal, slow); | 1167 __ j(not_equal, slow); |
| 1168 | 1168 |
| 1169 // This function is used only for loads, not stores, so it's safe to | 1169 // This function is used only for loads, not stores, so it's safe to |
| 1170 // return an rsi-based operand (the write barrier cannot be allowed to | 1170 // return an rsi-based operand (the write barrier cannot be allowed to |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1211 key_literal->handle()->IsSmi()) { | 1211 key_literal->handle()->IsSmi()) { |
| 1212 // Load arguments object if there are no eval-introduced | 1212 // Load arguments object if there are no eval-introduced |
| 1213 // variables. Then load the argument from the arguments | 1213 // variables. Then load the argument from the arguments |
| 1214 // object using keyed load. | 1214 // object using keyed load. |
| 1215 __ movq(rdx, | 1215 __ movq(rdx, |
| 1216 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), | 1216 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(), |
| 1217 slow)); | 1217 slow)); |
| 1218 __ Move(rax, key_literal->handle()); | 1218 __ Move(rax, key_literal->handle()); |
| 1219 Handle<Code> ic = | 1219 Handle<Code> ic = |
| 1220 isolate()->builtins()->KeyedLoadIC_Initialize(); | 1220 isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 1221 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); | 1221 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); |
| 1222 __ jmp(done); | 1222 __ jmp(done); |
| 1223 } | 1223 } |
| 1224 } | 1224 } |
| 1225 } | 1225 } |
| 1226 } | 1226 } |
| 1227 } | 1227 } |
| 1228 | 1228 |
| 1229 | 1229 |
| 1230 void FullCodeGenerator::EmitVariableLoad(Variable* var) { | 1230 void FullCodeGenerator::EmitVariableLoad(Variable* var) { |
| 1231 // Four cases: non-this global variables, lookup slots, all other | 1231 // Three cases: non-this global variables, lookup slots, and all other |
| 1232 // types of slots, and parameters that rewrite to explicit property | 1232 // types of slots. |
| 1233 // accesses on the arguments object. | |
| 1234 Slot* slot = var->AsSlot(); | 1233 Slot* slot = var->AsSlot(); |
| 1235 Property* property = var->AsProperty(); | 1234 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL)); |
| 1236 | 1235 |
| 1237 if (var->is_global() && !var->is_this()) { | 1236 if (slot == NULL) { |
| 1238 Comment cmnt(masm_, "Global variable"); | 1237 Comment cmnt(masm_, "Global variable"); |
| 1239 // Use inline caching. Variable name is passed in rcx and the global | 1238 // Use inline caching. Variable name is passed in rcx and the global |
| 1240 // object on the stack. | 1239 // object on the stack. |
| 1241 __ Move(rcx, var->name()); | 1240 __ Move(rcx, var->name()); |
| 1242 __ movq(rax, GlobalObjectOperand()); | 1241 __ movq(rax, GlobalObjectOperand()); |
| 1243 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1242 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 1244 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); | 1243 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1245 context()->Plug(rax); | 1244 context()->Plug(rax); |
| 1246 | 1245 |
| 1247 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1246 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 1248 Label done, slow; | 1247 Label done, slow; |
| 1249 | 1248 |
| 1250 // Generate code for loading from variables potentially shadowed | 1249 // Generate code for loading from variables potentially shadowed |
| 1251 // by eval-introduced variables. | 1250 // by eval-introduced variables. |
| 1252 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); | 1251 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1253 | 1252 |
| 1254 __ bind(&slow); | 1253 __ bind(&slow); |
| 1255 Comment cmnt(masm_, "Lookup slot"); | 1254 Comment cmnt(masm_, "Lookup slot"); |
| 1256 __ push(rsi); // Context. | 1255 __ push(rsi); // Context. |
| 1257 __ Push(var->name()); | 1256 __ Push(var->name()); |
| 1258 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1257 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1259 __ bind(&done); | 1258 __ bind(&done); |
| 1260 | 1259 |
| 1261 context()->Plug(rax); | 1260 context()->Plug(rax); |
| 1262 | 1261 |
| 1263 } else if (slot != NULL) { | 1262 } else { |
| 1264 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) | 1263 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) |
| 1265 ? "Context slot" | 1264 ? "Context slot" |
| 1266 : "Stack slot"); | 1265 : "Stack slot"); |
| 1267 if (var->mode() == Variable::CONST) { | 1266 if (var->mode() == Variable::CONST) { |
| 1268 // Constants may be the hole value if they have not been initialized. | 1267 // Constants may be the hole value if they have not been initialized. |
| 1269 // Unhole them. | 1268 // Unhole them. |
| 1270 Label done; | 1269 Label done; |
| 1271 MemOperand slot_operand = EmitSlotSearch(slot, rax); | 1270 MemOperand slot_operand = EmitSlotSearch(slot, rax); |
| 1272 __ movq(rax, slot_operand); | 1271 __ movq(rax, slot_operand); |
| 1273 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 1272 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
| 1274 __ j(not_equal, &done, Label::kNear); | 1273 __ j(not_equal, &done, Label::kNear); |
| 1275 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 1274 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 1276 __ bind(&done); | 1275 __ bind(&done); |
| 1277 context()->Plug(rax); | 1276 context()->Plug(rax); |
| 1278 } else { | 1277 } else { |
| 1279 context()->Plug(slot); | 1278 context()->Plug(slot); |
| 1280 } | 1279 } |
| 1281 | |
| 1282 } else { | |
| 1283 Comment cmnt(masm_, "Rewritten parameter"); | |
| 1284 ASSERT_NOT_NULL(property); | |
| 1285 // Rewritten parameter accesses are of the form "slot[literal]". | |
| 1286 | |
| 1287 // Assert that the object is in a slot. | |
| 1288 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); | |
| 1289 ASSERT_NOT_NULL(object_var); | |
| 1290 Slot* object_slot = object_var->AsSlot(); | |
| 1291 ASSERT_NOT_NULL(object_slot); | |
| 1292 | |
| 1293 // Load the object. | |
| 1294 MemOperand object_loc = EmitSlotSearch(object_slot, rax); | |
| 1295 __ movq(rdx, object_loc); | |
| 1296 | |
| 1297 // Assert that the key is a smi. | |
| 1298 Literal* key_literal = property->key()->AsLiteral(); | |
| 1299 ASSERT_NOT_NULL(key_literal); | |
| 1300 ASSERT(key_literal->handle()->IsSmi()); | |
| 1301 | |
| 1302 // Load the key. | |
| 1303 __ Move(rax, key_literal->handle()); | |
| 1304 | |
| 1305 // Do a keyed property load. | |
| 1306 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | |
| 1307 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(property)); | |
| 1308 context()->Plug(rax); | |
| 1309 } | 1280 } |
| 1310 } | 1281 } |
| 1311 | 1282 |
| 1312 | 1283 |
| 1313 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { | 1284 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { |
| 1314 Comment cmnt(masm_, "[ RegExpLiteral"); | 1285 Comment cmnt(masm_, "[ RegExpLiteral"); |
| 1315 Label materialized; | 1286 Label materialized; |
| 1316 // Registers will be used as follows: | 1287 // Registers will be used as follows: |
| 1317 // rdi = JS function. | 1288 // rdi = JS function. |
| 1318 // rcx = literals array. | 1289 // rcx = literals array. |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1410 // Fall through. | 1381 // Fall through. |
| 1411 case ObjectLiteral::Property::COMPUTED: | 1382 case ObjectLiteral::Property::COMPUTED: |
| 1412 if (key->handle()->IsSymbol()) { | 1383 if (key->handle()->IsSymbol()) { |
| 1413 if (property->emit_store()) { | 1384 if (property->emit_store()) { |
| 1414 VisitForAccumulatorValue(value); | 1385 VisitForAccumulatorValue(value); |
| 1415 __ Move(rcx, key->handle()); | 1386 __ Move(rcx, key->handle()); |
| 1416 __ movq(rdx, Operand(rsp, 0)); | 1387 __ movq(rdx, Operand(rsp, 0)); |
| 1417 Handle<Code> ic = is_strict_mode() | 1388 Handle<Code> ic = is_strict_mode() |
| 1418 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1389 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 1419 : isolate()->builtins()->StoreIC_Initialize(); | 1390 : isolate()->builtins()->StoreIC_Initialize(); |
| 1420 EmitCallIC(ic, RelocInfo::CODE_TARGET, key->id()); | 1391 __ call(ic, RelocInfo::CODE_TARGET, key->id()); |
| 1421 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1392 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1422 } else { | 1393 } else { |
| 1423 VisitForEffect(value); | 1394 VisitForEffect(value); |
| 1424 } | 1395 } |
| 1425 break; | 1396 break; |
| 1426 } | 1397 } |
| 1427 // Fall through. | 1398 // Fall through. |
| 1428 case ObjectLiteral::Property::PROTOTYPE: | 1399 case ObjectLiteral::Property::PROTOTYPE: |
| 1429 __ push(Operand(rsp, 0)); // Duplicate receiver. | 1400 __ push(Operand(rsp, 0)); // Duplicate receiver. |
| 1430 VisitForStackValue(key); | 1401 VisitForStackValue(key); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1531 void FullCodeGenerator::VisitAssignment(Assignment* expr) { | 1502 void FullCodeGenerator::VisitAssignment(Assignment* expr) { |
| 1532 Comment cmnt(masm_, "[ Assignment"); | 1503 Comment cmnt(masm_, "[ Assignment"); |
| 1533 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' | 1504 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError' |
| 1534 // on the left-hand side. | 1505 // on the left-hand side. |
| 1535 if (!expr->target()->IsValidLeftHandSide()) { | 1506 if (!expr->target()->IsValidLeftHandSide()) { |
| 1536 VisitForEffect(expr->target()); | 1507 VisitForEffect(expr->target()); |
| 1537 return; | 1508 return; |
| 1538 } | 1509 } |
| 1539 | 1510 |
| 1540 // Left-hand side can only be a property, a global or a (parameter or local) | 1511 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1541 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1512 // slot. |
| 1542 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1513 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1543 LhsKind assign_type = VARIABLE; | 1514 LhsKind assign_type = VARIABLE; |
| 1544 Property* property = expr->target()->AsProperty(); | 1515 Property* property = expr->target()->AsProperty(); |
| 1545 if (property != NULL) { | 1516 if (property != NULL) { |
| 1546 assign_type = (property->key()->IsPropertyName()) | 1517 assign_type = (property->key()->IsPropertyName()) |
| 1547 ? NAMED_PROPERTY | 1518 ? NAMED_PROPERTY |
| 1548 : KEYED_PROPERTY; | 1519 : KEYED_PROPERTY; |
| 1549 } | 1520 } |
| 1550 | 1521 |
| 1551 // Evaluate LHS expression. | 1522 // Evaluate LHS expression. |
| 1552 switch (assign_type) { | 1523 switch (assign_type) { |
| 1553 case VARIABLE: | 1524 case VARIABLE: |
| 1554 // Nothing to do here. | 1525 // Nothing to do here. |
| 1555 break; | 1526 break; |
| 1556 case NAMED_PROPERTY: | 1527 case NAMED_PROPERTY: |
| 1557 if (expr->is_compound()) { | 1528 if (expr->is_compound()) { |
| 1558 // We need the receiver both on the stack and in the accumulator. | 1529 // We need the receiver both on the stack and in the accumulator. |
| 1559 VisitForAccumulatorValue(property->obj()); | 1530 VisitForAccumulatorValue(property->obj()); |
| 1560 __ push(result_register()); | 1531 __ push(result_register()); |
| 1561 } else { | 1532 } else { |
| 1562 VisitForStackValue(property->obj()); | 1533 VisitForStackValue(property->obj()); |
| 1563 } | 1534 } |
| 1564 break; | 1535 break; |
| 1565 case KEYED_PROPERTY: { | 1536 case KEYED_PROPERTY: { |
| 1566 if (expr->is_compound()) { | 1537 if (expr->is_compound()) { |
| 1567 if (property->is_arguments_access()) { | 1538 VisitForStackValue(property->obj()); |
| 1568 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1539 VisitForAccumulatorValue(property->key()); |
| 1569 MemOperand slot_operand = | |
| 1570 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); | |
| 1571 __ push(slot_operand); | |
| 1572 __ Move(rax, property->key()->AsLiteral()->handle()); | |
| 1573 } else { | |
| 1574 VisitForStackValue(property->obj()); | |
| 1575 VisitForAccumulatorValue(property->key()); | |
| 1576 } | |
| 1577 __ movq(rdx, Operand(rsp, 0)); | 1540 __ movq(rdx, Operand(rsp, 0)); |
| 1578 __ push(rax); | 1541 __ push(rax); |
| 1579 } else { | 1542 } else { |
| 1580 if (property->is_arguments_access()) { | 1543 VisitForStackValue(property->obj()); |
| 1581 VariableProxy* obj_proxy = property->obj()->AsVariableProxy(); | 1544 VisitForStackValue(property->key()); |
| 1582 MemOperand slot_operand = | |
| 1583 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); | |
| 1584 __ push(slot_operand); | |
| 1585 __ Push(property->key()->AsLiteral()->handle()); | |
| 1586 } else { | |
| 1587 VisitForStackValue(property->obj()); | |
| 1588 VisitForStackValue(property->key()); | |
| 1589 } | |
| 1590 } | 1545 } |
| 1591 break; | 1546 break; |
| 1592 } | 1547 } |
| 1593 } | 1548 } |
| 1594 | 1549 |
| 1595 // For compound assignments we need another deoptimization point after the | 1550 // For compound assignments we need another deoptimization point after the |
| 1596 // variable/property load. | 1551 // variable/property load. |
| 1597 if (expr->is_compound()) { | 1552 if (expr->is_compound()) { |
| 1598 { AccumulatorValueContext context(this); | 1553 { AccumulatorValueContext context(this); |
| 1599 switch (assign_type) { | 1554 switch (assign_type) { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1655 break; | 1610 break; |
| 1656 } | 1611 } |
| 1657 } | 1612 } |
| 1658 | 1613 |
| 1659 | 1614 |
| 1660 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { | 1615 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) { |
| 1661 SetSourcePosition(prop->position()); | 1616 SetSourcePosition(prop->position()); |
| 1662 Literal* key = prop->key()->AsLiteral(); | 1617 Literal* key = prop->key()->AsLiteral(); |
| 1663 __ Move(rcx, key->handle()); | 1618 __ Move(rcx, key->handle()); |
| 1664 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 1619 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 1665 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | 1620 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); |
| 1666 } | 1621 } |
| 1667 | 1622 |
| 1668 | 1623 |
| 1669 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 1624 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 1670 SetSourcePosition(prop->position()); | 1625 SetSourcePosition(prop->position()); |
| 1671 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 1626 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 1672 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | 1627 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); |
| 1673 } | 1628 } |
| 1674 | 1629 |
| 1675 | 1630 |
| 1676 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, | 1631 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, |
| 1677 Token::Value op, | 1632 Token::Value op, |
| 1678 OverwriteMode mode, | 1633 OverwriteMode mode, |
| 1679 Expression* left, | 1634 Expression* left, |
| 1680 Expression* right) { | 1635 Expression* right) { |
| 1681 // Do combined smi check of the operands. Left operand is on the | 1636 // Do combined smi check of the operands. Left operand is on the |
| 1682 // stack (popped into rdx). Right operand is in rax but moved into | 1637 // stack (popped into rdx). Right operand is in rax but moved into |
| 1683 // rcx to make the shifts easier. | 1638 // rcx to make the shifts easier. |
| 1684 Label done, stub_call, smi_case; | 1639 Label done, stub_call, smi_case; |
| 1685 __ pop(rdx); | 1640 __ pop(rdx); |
| 1686 __ movq(rcx, rax); | 1641 __ movq(rcx, rax); |
| 1687 __ or_(rax, rdx); | 1642 __ or_(rax, rdx); |
| 1688 JumpPatchSite patch_site(masm_); | 1643 JumpPatchSite patch_site(masm_); |
| 1689 patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear); | 1644 patch_site.EmitJumpIfSmi(rax, &smi_case, Label::kNear); |
| 1690 | 1645 |
| 1691 __ bind(&stub_call); | 1646 __ bind(&stub_call); |
| 1692 __ movq(rax, rcx); | 1647 __ movq(rax, rcx); |
| 1693 BinaryOpStub stub(op, mode); | 1648 BinaryOpStub stub(op, mode); |
| 1694 EmitCallIC(stub.GetCode(), &patch_site, expr->id()); | 1649 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| 1650 patch_site.EmitPatchInfo(); |
| 1695 __ jmp(&done, Label::kNear); | 1651 __ jmp(&done, Label::kNear); |
| 1696 | 1652 |
| 1697 __ bind(&smi_case); | 1653 __ bind(&smi_case); |
| 1698 switch (op) { | 1654 switch (op) { |
| 1699 case Token::SAR: | 1655 case Token::SAR: |
| 1700 __ SmiShiftArithmeticRight(rax, rdx, rcx); | 1656 __ SmiShiftArithmeticRight(rax, rdx, rcx); |
| 1701 break; | 1657 break; |
| 1702 case Token::SHL: | 1658 case Token::SHL: |
| 1703 __ SmiShiftLeft(rax, rdx, rcx); | 1659 __ SmiShiftLeft(rax, rdx, rcx); |
| 1704 break; | 1660 break; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1731 __ bind(&done); | 1687 __ bind(&done); |
| 1732 context()->Plug(rax); | 1688 context()->Plug(rax); |
| 1733 } | 1689 } |
| 1734 | 1690 |
| 1735 | 1691 |
| 1736 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, | 1692 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, |
| 1737 Token::Value op, | 1693 Token::Value op, |
| 1738 OverwriteMode mode) { | 1694 OverwriteMode mode) { |
| 1739 __ pop(rdx); | 1695 __ pop(rdx); |
| 1740 BinaryOpStub stub(op, mode); | 1696 BinaryOpStub stub(op, mode); |
| 1741 // NULL signals no inlined smi code. | 1697 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
| 1742 EmitCallIC(stub.GetCode(), NULL, expr->id()); | 1698 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| 1699 patch_site.EmitPatchInfo(); |
| 1743 context()->Plug(rax); | 1700 context()->Plug(rax); |
| 1744 } | 1701 } |
| 1745 | 1702 |
| 1746 | 1703 |
| 1747 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { | 1704 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { |
| 1748 // Invalid left-hand sides are rewritten to have a 'throw | 1705 // Invalid left-hand sides are rewritten to have a 'throw |
| 1749 // ReferenceError' on the left-hand side. | 1706 // ReferenceError' on the left-hand side. |
| 1750 if (!expr->IsValidLeftHandSide()) { | 1707 if (!expr->IsValidLeftHandSide()) { |
| 1751 VisitForEffect(expr); | 1708 VisitForEffect(expr); |
| 1752 return; | 1709 return; |
| 1753 } | 1710 } |
| 1754 | 1711 |
| 1755 // Left-hand side can only be a property, a global or a (parameter or local) | 1712 // Left-hand side can only be a property, a global or a (parameter or local) |
| 1756 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 1713 // slot. |
| 1757 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 1714 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 1758 LhsKind assign_type = VARIABLE; | 1715 LhsKind assign_type = VARIABLE; |
| 1759 Property* prop = expr->AsProperty(); | 1716 Property* prop = expr->AsProperty(); |
| 1760 if (prop != NULL) { | 1717 if (prop != NULL) { |
| 1761 assign_type = (prop->key()->IsPropertyName()) | 1718 assign_type = (prop->key()->IsPropertyName()) |
| 1762 ? NAMED_PROPERTY | 1719 ? NAMED_PROPERTY |
| 1763 : KEYED_PROPERTY; | 1720 : KEYED_PROPERTY; |
| 1764 } | 1721 } |
| 1765 | 1722 |
| 1766 switch (assign_type) { | 1723 switch (assign_type) { |
| 1767 case VARIABLE: { | 1724 case VARIABLE: { |
| 1768 Variable* var = expr->AsVariableProxy()->var(); | 1725 Variable* var = expr->AsVariableProxy()->var(); |
| 1769 EffectContext context(this); | 1726 EffectContext context(this); |
| 1770 EmitVariableAssignment(var, Token::ASSIGN); | 1727 EmitVariableAssignment(var, Token::ASSIGN); |
| 1771 break; | 1728 break; |
| 1772 } | 1729 } |
| 1773 case NAMED_PROPERTY: { | 1730 case NAMED_PROPERTY: { |
| 1774 __ push(rax); // Preserve value. | 1731 __ push(rax); // Preserve value. |
| 1775 VisitForAccumulatorValue(prop->obj()); | 1732 VisitForAccumulatorValue(prop->obj()); |
| 1776 __ movq(rdx, rax); | 1733 __ movq(rdx, rax); |
| 1777 __ pop(rax); // Restore value. | 1734 __ pop(rax); // Restore value. |
| 1778 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1735 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 1779 Handle<Code> ic = is_strict_mode() | 1736 Handle<Code> ic = is_strict_mode() |
| 1780 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1737 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 1781 : isolate()->builtins()->StoreIC_Initialize(); | 1738 : isolate()->builtins()->StoreIC_Initialize(); |
| 1782 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 1739 __ call(ic); |
| 1783 break; | 1740 break; |
| 1784 } | 1741 } |
| 1785 case KEYED_PROPERTY: { | 1742 case KEYED_PROPERTY: { |
| 1786 __ push(rax); // Preserve value. | 1743 __ push(rax); // Preserve value. |
| 1787 if (prop->is_synthetic()) { | 1744 VisitForStackValue(prop->obj()); |
| 1788 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 1745 VisitForAccumulatorValue(prop->key()); |
| 1789 ASSERT(prop->key()->AsLiteral() != NULL); | 1746 __ movq(rcx, rax); |
| 1790 { AccumulatorValueContext for_object(this); | 1747 __ pop(rdx); |
| 1791 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | |
| 1792 } | |
| 1793 __ movq(rdx, rax); | |
| 1794 __ Move(rcx, prop->key()->AsLiteral()->handle()); | |
| 1795 } else { | |
| 1796 VisitForStackValue(prop->obj()); | |
| 1797 VisitForAccumulatorValue(prop->key()); | |
| 1798 __ movq(rcx, rax); | |
| 1799 __ pop(rdx); | |
| 1800 } | |
| 1801 __ pop(rax); // Restore value. | 1748 __ pop(rax); // Restore value. |
| 1802 Handle<Code> ic = is_strict_mode() | 1749 Handle<Code> ic = is_strict_mode() |
| 1803 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 1750 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 1804 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 1751 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 1805 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 1752 __ call(ic); |
| 1806 break; | 1753 break; |
| 1807 } | 1754 } |
| 1808 } | 1755 } |
| 1809 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1756 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| 1810 context()->Plug(rax); | 1757 context()->Plug(rax); |
| 1811 } | 1758 } |
| 1812 | 1759 |
| 1813 | 1760 |
| 1814 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1761 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1815 Token::Value op) { | 1762 Token::Value op) { |
| 1816 // Left-hand sides that rewrite to explicit property accesses do not reach | |
| 1817 // here. | |
| 1818 ASSERT(var != NULL); | 1763 ASSERT(var != NULL); |
| 1819 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1764 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| 1820 | 1765 |
| 1821 if (var->is_global()) { | 1766 if (var->is_global()) { |
| 1822 ASSERT(!var->is_this()); | 1767 ASSERT(!var->is_this()); |
| 1823 // Assignment to a global variable. Use inline caching for the | 1768 // Assignment to a global variable. Use inline caching for the |
| 1824 // assignment. Right-hand-side value is passed in rax, variable name in | 1769 // assignment. Right-hand-side value is passed in rax, variable name in |
| 1825 // rcx, and the global object on the stack. | 1770 // rcx, and the global object on the stack. |
| 1826 __ Move(rcx, var->name()); | 1771 __ Move(rcx, var->name()); |
| 1827 __ movq(rdx, GlobalObjectOperand()); | 1772 __ movq(rdx, GlobalObjectOperand()); |
| 1828 Handle<Code> ic = is_strict_mode() | 1773 Handle<Code> ic = is_strict_mode() |
| 1829 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1774 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 1830 : isolate()->builtins()->StoreIC_Initialize(); | 1775 : isolate()->builtins()->StoreIC_Initialize(); |
| 1831 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT, AstNode::kNoNumber); | 1776 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1832 | 1777 |
| 1833 } else if (op == Token::INIT_CONST) { | 1778 } else if (op == Token::INIT_CONST) { |
| 1834 // Like var declarations, const declarations are hoisted to function | 1779 // Like var declarations, const declarations are hoisted to function |
| 1835 // scope. However, unlike var initializers, const initializers are able | 1780 // scope. However, unlike var initializers, const initializers are able |
| 1836 // to drill a hole to that function context, even from inside a 'with' | 1781 // to drill a hole to that function context, even from inside a 'with' |
| 1837 // context. We thus bypass the normal static scope lookup. | 1782 // context. We thus bypass the normal static scope lookup. |
| 1838 Slot* slot = var->AsSlot(); | 1783 Slot* slot = var->AsSlot(); |
| 1839 Label skip; | 1784 Label skip; |
| 1840 switch (slot->type()) { | 1785 switch (slot->type()) { |
| 1841 case Slot::PARAMETER: | 1786 case Slot::PARAMETER: |
| 1842 // No const parameters. | 1787 // No const parameters. |
| 1843 UNREACHABLE(); | 1788 UNREACHABLE(); |
| 1844 break; | 1789 break; |
| 1845 case Slot::LOCAL: | 1790 case Slot::LOCAL: |
| 1846 __ movq(rdx, Operand(rbp, SlotOffset(slot))); | 1791 __ movq(rdx, Operand(rbp, SlotOffset(slot))); |
| 1847 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | 1792 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 1848 __ j(not_equal, &skip); | 1793 __ j(not_equal, &skip); |
| 1849 __ movq(Operand(rbp, SlotOffset(slot)), rax); | 1794 __ movq(Operand(rbp, SlotOffset(slot)), rax); |
| 1850 break; | 1795 break; |
| 1851 case Slot::CONTEXT: { | 1796 case Slot::CONTEXT: |
| 1852 __ movq(rcx, ContextOperand(rsi, Context::FCONTEXT_INDEX)); | |
| 1853 __ movq(rdx, ContextOperand(rcx, slot->index())); | |
| 1854 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | |
| 1855 __ j(not_equal, &skip); | |
| 1856 __ movq(ContextOperand(rcx, slot->index()), rax); | |
| 1857 int offset = Context::SlotOffset(slot->index()); | |
| 1858 __ movq(rdx, rax); // Preserve the stored value in eax. | |
| 1859 __ RecordWriteContextSlot(rcx, offset, rdx, rbx, kDontSaveFPRegs); | |
| 1860 break; | |
| 1861 } | |
| 1862 case Slot::LOOKUP: | 1797 case Slot::LOOKUP: |
| 1863 __ push(rax); | 1798 __ push(rax); |
| 1864 __ push(rsi); | 1799 __ push(rsi); |
| 1865 __ Push(var->name()); | 1800 __ Push(var->name()); |
| 1866 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 1801 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 1867 break; | 1802 break; |
| 1868 } | 1803 } |
| 1869 __ bind(&skip); | 1804 __ bind(&skip); |
| 1870 | 1805 |
| 1871 } else if (var->mode() != Variable::CONST) { | 1806 } else if (var->mode() != Variable::CONST) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1925 SetSourcePosition(expr->position()); | 1860 SetSourcePosition(expr->position()); |
| 1926 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1861 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 1927 if (expr->ends_initialization_block()) { | 1862 if (expr->ends_initialization_block()) { |
| 1928 __ movq(rdx, Operand(rsp, 0)); | 1863 __ movq(rdx, Operand(rsp, 0)); |
| 1929 } else { | 1864 } else { |
| 1930 __ pop(rdx); | 1865 __ pop(rdx); |
| 1931 } | 1866 } |
| 1932 Handle<Code> ic = is_strict_mode() | 1867 Handle<Code> ic = is_strict_mode() |
| 1933 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 1868 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 1934 : isolate()->builtins()->StoreIC_Initialize(); | 1869 : isolate()->builtins()->StoreIC_Initialize(); |
| 1935 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 1870 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 1936 | 1871 |
| 1937 // If the assignment ends an initialization block, revert to fast case. | 1872 // If the assignment ends an initialization block, revert to fast case. |
| 1938 if (expr->ends_initialization_block()) { | 1873 if (expr->ends_initialization_block()) { |
| 1939 __ push(rax); // Result of assignment, saved even if not needed. | 1874 __ push(rax); // Result of assignment, saved even if not needed. |
| 1940 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 1875 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. |
| 1941 __ CallRuntime(Runtime::kToFastProperties, 1); | 1876 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1942 __ pop(rax); | 1877 __ pop(rax); |
| 1943 __ Drop(1); | 1878 __ Drop(1); |
| 1944 } | 1879 } |
| 1945 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 1880 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1965 if (expr->ends_initialization_block()) { | 1900 if (expr->ends_initialization_block()) { |
| 1966 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later. | 1901 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later. |
| 1967 } else { | 1902 } else { |
| 1968 __ pop(rdx); | 1903 __ pop(rdx); |
| 1969 } | 1904 } |
| 1970 // Record source code position before IC call. | 1905 // Record source code position before IC call. |
| 1971 SetSourcePosition(expr->position()); | 1906 SetSourcePosition(expr->position()); |
| 1972 Handle<Code> ic = is_strict_mode() | 1907 Handle<Code> ic = is_strict_mode() |
| 1973 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 1908 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 1974 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 1909 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 1975 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 1910 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 1976 | 1911 |
| 1977 // If the assignment ends an initialization block, revert to fast case. | 1912 // If the assignment ends an initialization block, revert to fast case. |
| 1978 if (expr->ends_initialization_block()) { | 1913 if (expr->ends_initialization_block()) { |
| 1979 __ pop(rdx); | 1914 __ pop(rdx); |
| 1980 __ push(rax); // Result of assignment, saved even if not needed. | 1915 __ push(rax); // Result of assignment, saved even if not needed. |
| 1981 __ push(rdx); | 1916 __ push(rdx); |
| 1982 __ CallRuntime(Runtime::kToFastProperties, 1); | 1917 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1983 __ pop(rax); | 1918 __ pop(rax); |
| 1984 } | 1919 } |
| 1985 | 1920 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2017 VisitForStackValue(args->at(i)); | 1952 VisitForStackValue(args->at(i)); |
| 2018 } | 1953 } |
| 2019 __ Move(rcx, name); | 1954 __ Move(rcx, name); |
| 2020 } | 1955 } |
| 2021 // Record source position for debugger. | 1956 // Record source position for debugger. |
| 2022 SetSourcePosition(expr->position()); | 1957 SetSourcePosition(expr->position()); |
| 2023 // Call the IC initialization code. | 1958 // Call the IC initialization code. |
| 2024 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1959 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2025 Handle<Code> ic = | 1960 Handle<Code> ic = |
| 2026 ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); | 1961 ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); |
| 2027 EmitCallIC(ic, mode, expr->id()); | 1962 __ call(ic, mode, expr->id()); |
| 2028 RecordJSReturnSite(expr); | 1963 RecordJSReturnSite(expr); |
| 2029 // Restore context register. | 1964 // Restore context register. |
| 2030 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1965 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2031 context()->Plug(rax); | 1966 context()->Plug(rax); |
| 2032 } | 1967 } |
| 2033 | 1968 |
| 2034 | 1969 |
| 2035 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 1970 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 2036 Expression* key) { | 1971 Expression* key) { |
| 2037 // Load the key. | 1972 // Load the key. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2051 VisitForStackValue(args->at(i)); | 1986 VisitForStackValue(args->at(i)); |
| 2052 } | 1987 } |
| 2053 } | 1988 } |
| 2054 // Record source position for debugger. | 1989 // Record source position for debugger. |
| 2055 SetSourcePosition(expr->position()); | 1990 SetSourcePosition(expr->position()); |
| 2056 // Call the IC initialization code. | 1991 // Call the IC initialization code. |
| 2057 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 1992 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2058 Handle<Code> ic = | 1993 Handle<Code> ic = |
| 2059 ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop); | 1994 ISOLATE->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop); |
| 2060 __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key. | 1995 __ movq(rcx, Operand(rsp, (arg_count + 1) * kPointerSize)); // Key. |
| 2061 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 1996 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 2062 RecordJSReturnSite(expr); | 1997 RecordJSReturnSite(expr); |
| 2063 // Restore context register. | 1998 // Restore context register. |
| 2064 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 1999 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2065 context()->DropAndPlug(1, rax); // Drop the key still on the stack. | 2000 context()->DropAndPlug(1, rax); // Drop the key still on the stack. |
| 2066 } | 2001 } |
| 2067 | 2002 |
| 2068 | 2003 |
| 2069 void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { | 2004 void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) { |
| 2070 // Code common for calls using the call stub. | 2005 // Code common for calls using the call stub. |
| 2071 ZoneList<Expression*>* args = expr->arguments(); | 2006 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2091 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, | 2026 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, |
| 2092 int arg_count) { | 2027 int arg_count) { |
| 2093 // Push copy of the first argument or undefined if it doesn't exist. | 2028 // Push copy of the first argument or undefined if it doesn't exist. |
| 2094 if (arg_count > 0) { | 2029 if (arg_count > 0) { |
| 2095 __ push(Operand(rsp, arg_count * kPointerSize)); | 2030 __ push(Operand(rsp, arg_count * kPointerSize)); |
| 2096 } else { | 2031 } else { |
| 2097 __ PushRoot(Heap::kUndefinedValueRootIndex); | 2032 __ PushRoot(Heap::kUndefinedValueRootIndex); |
| 2098 } | 2033 } |
| 2099 | 2034 |
| 2100 // Push the receiver of the enclosing function and do runtime call. | 2035 // Push the receiver of the enclosing function and do runtime call. |
| 2101 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize)); | 2036 __ push(Operand(rbp, (2 + info_->scope()->num_parameters()) * kPointerSize)); |
| 2102 | 2037 |
| 2103 // Push the strict mode flag. | 2038 // Push the strict mode flag. |
| 2104 __ Push(Smi::FromInt(strict_mode_flag())); | 2039 __ Push(Smi::FromInt(strict_mode_flag())); |
| 2105 | 2040 |
| 2106 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP | 2041 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP |
| 2107 ? Runtime::kResolvePossiblyDirectEvalNoLookup | 2042 ? Runtime::kResolvePossiblyDirectEvalNoLookup |
| 2108 : Runtime::kResolvePossiblyDirectEval, 4); | 2043 : Runtime::kResolvePossiblyDirectEval, 4); |
| 2109 } | 2044 } |
| 2110 | 2045 |
| 2111 | 2046 |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2205 | 2140 |
| 2206 // If fast case code has been generated, emit code to push the | 2141 // If fast case code has been generated, emit code to push the |
| 2207 // function and receiver and have the slow path jump around this | 2142 // function and receiver and have the slow path jump around this |
| 2208 // code. | 2143 // code. |
| 2209 if (done.is_linked()) { | 2144 if (done.is_linked()) { |
| 2210 Label call; | 2145 Label call; |
| 2211 __ jmp(&call, Label::kNear); | 2146 __ jmp(&call, Label::kNear); |
| 2212 __ bind(&done); | 2147 __ bind(&done); |
| 2213 // Push function. | 2148 // Push function. |
| 2214 __ push(rax); | 2149 __ push(rax); |
| 2215 // Push global receiver. | 2150 // The receiver is implicitly the global receiver. Indicate this |
| 2216 __ movq(rbx, GlobalObjectOperand()); | 2151 // by passing the hole to the call function stub. |
| 2217 __ push(FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); | 2152 __ PushRoot(Heap::kTheHoleValueRootIndex); |
| 2218 __ bind(&call); | 2153 __ bind(&call); |
| 2219 } | 2154 } |
| 2220 | 2155 |
| 2221 // The receiver is either the global receiver or an object found | 2156 // The receiver is either the global receiver or an object found |
| 2222 // by LoadContextSlot. That object could be the hole if the | 2157 // by LoadContextSlot. That object could be the hole if the |
| 2223 // receiver is implicitly the global object. | 2158 // receiver is implicitly the global object. |
| 2224 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); | 2159 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT); |
| 2225 } else if (fun->AsProperty() != NULL) { | 2160 } else if (fun->AsProperty() != NULL) { |
| 2226 // Call to an object property. | 2161 // Call to an object property. |
| 2227 Property* prop = fun->AsProperty(); | 2162 Property* prop = fun->AsProperty(); |
| 2228 Literal* key = prop->key()->AsLiteral(); | 2163 Literal* key = prop->key()->AsLiteral(); |
| 2229 if (key != NULL && key->handle()->IsSymbol()) { | 2164 if (key != NULL && key->handle()->IsSymbol()) { |
| 2230 // Call to a named property, use call IC. | 2165 // Call to a named property, use call IC. |
| 2231 { PreservePositionScope scope(masm()->positions_recorder()); | 2166 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2232 VisitForStackValue(prop->obj()); | 2167 VisitForStackValue(prop->obj()); |
| 2233 } | 2168 } |
| 2234 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2169 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 2235 } else { | 2170 } else { |
| 2236 // Call to a keyed property. | 2171 // Call to a keyed property. |
| 2237 // For a synthetic property use keyed load IC followed by function call, | 2172 // For a synthetic property use keyed load IC followed by function call, |
| 2238 // for a regular property use keyed EmitCallIC. | 2173 // for a regular property use EmitKeyedCallWithIC. |
| 2239 if (prop->is_synthetic()) { | 2174 if (prop->is_synthetic()) { |
| 2240 // Do not visit the object and key subexpressions (they are shared | 2175 // Do not visit the object and key subexpressions (they are shared |
| 2241 // by all occurrences of the same rewritten parameter). | 2176 // by all occurrences of the same rewritten parameter). |
| 2242 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 2177 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 2243 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); | 2178 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); |
| 2244 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); | 2179 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); |
| 2245 MemOperand operand = EmitSlotSearch(slot, rdx); | 2180 MemOperand operand = EmitSlotSearch(slot, rdx); |
| 2246 __ movq(rdx, operand); | 2181 __ movq(rdx, operand); |
| 2247 | 2182 |
| 2248 ASSERT(prop->key()->AsLiteral() != NULL); | 2183 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2249 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); | 2184 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); |
| 2250 __ Move(rax, prop->key()->AsLiteral()->handle()); | 2185 __ Move(rax, prop->key()->AsLiteral()->handle()); |
| 2251 | 2186 |
| 2252 // Record source code position for IC call. | 2187 // Record source code position for IC call. |
| 2253 SetSourcePosition(prop->position()); | 2188 SetSourcePosition(prop->position()); |
| 2254 | 2189 |
| 2255 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 2190 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2256 EmitCallIC(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); | 2191 __ call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop)); |
| 2257 // Push result (function). | 2192 // Push result (function). |
| 2258 __ push(rax); | 2193 __ push(rax); |
| 2259 // Push Global receiver. | 2194 // Push Global receiver. |
| 2260 __ movq(rcx, GlobalObjectOperand()); | 2195 __ movq(rcx, GlobalObjectOperand()); |
| 2261 __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset)); | 2196 __ push(FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset)); |
| 2262 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); | 2197 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS); |
| 2263 } else { | 2198 } else { |
| 2264 { PreservePositionScope scope(masm()->positions_recorder()); | 2199 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2265 VisitForStackValue(prop->obj()); | 2200 VisitForStackValue(prop->obj()); |
| 2266 } | 2201 } |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2372 | 2307 |
| 2373 __ JumpIfSmi(rax, if_false); | 2308 __ JumpIfSmi(rax, if_false); |
| 2374 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 2309 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 2375 __ j(equal, if_true); | 2310 __ j(equal, if_true); |
| 2376 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); | 2311 __ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 2377 // Undetectable objects behave like undefined when tested with typeof. | 2312 // Undetectable objects behave like undefined when tested with typeof. |
| 2378 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 2313 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 2379 Immediate(1 << Map::kIsUndetectable)); | 2314 Immediate(1 << Map::kIsUndetectable)); |
| 2380 __ j(not_zero, if_false); | 2315 __ j(not_zero, if_false); |
| 2381 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); | 2316 __ movzxbq(rbx, FieldOperand(rbx, Map::kInstanceTypeOffset)); |
| 2382 __ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE)); | 2317 __ cmpq(rbx, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 2383 __ j(below, if_false); | 2318 __ j(below, if_false); |
| 2384 __ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE)); | 2319 __ cmpq(rbx, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 2385 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 2320 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2386 Split(below_equal, if_true, if_false, fall_through); | 2321 Split(below_equal, if_true, if_false, fall_through); |
| 2387 | 2322 |
| 2388 context()->Plug(if_true, if_false); | 2323 context()->Plug(if_true, if_false); |
| 2389 } | 2324 } |
| 2390 | 2325 |
| 2391 | 2326 |
| 2392 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { | 2327 void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) { |
| 2393 ASSERT(args->length() == 1); | 2328 ASSERT(args->length() == 1); |
| 2394 | 2329 |
| 2395 VisitForAccumulatorValue(args->at(0)); | 2330 VisitForAccumulatorValue(args->at(0)); |
| 2396 | 2331 |
| 2397 Label materialize_true, materialize_false; | 2332 Label materialize_true, materialize_false; |
| 2398 Label* if_true = NULL; | 2333 Label* if_true = NULL; |
| 2399 Label* if_false = NULL; | 2334 Label* if_false = NULL; |
| 2400 Label* fall_through = NULL; | 2335 Label* fall_through = NULL; |
| 2401 context()->PrepareTest(&materialize_true, &materialize_false, | 2336 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2402 &if_true, &if_false, &fall_through); | 2337 &if_true, &if_false, &fall_through); |
| 2403 | 2338 |
| 2404 __ JumpIfSmi(rax, if_false); | 2339 __ JumpIfSmi(rax, if_false); |
| 2405 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | 2340 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx); |
| 2406 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 2341 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2407 Split(above_equal, if_true, if_false, fall_through); | 2342 Split(above_equal, if_true, if_false, fall_through); |
| 2408 | 2343 |
| 2409 context()->Plug(if_true, if_false); | 2344 context()->Plug(if_true, if_false); |
| 2410 } | 2345 } |
| 2411 | 2346 |
| 2412 | 2347 |
| 2413 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { | 2348 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) { |
| 2414 ASSERT(args->length() == 1); | 2349 ASSERT(args->length() == 1); |
| 2415 | 2350 |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2633 } | 2568 } |
| 2634 | 2569 |
| 2635 | 2570 |
| 2636 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { | 2571 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) { |
| 2637 ASSERT(args->length() == 1); | 2572 ASSERT(args->length() == 1); |
| 2638 | 2573 |
| 2639 // ArgumentsAccessStub expects the key in rdx and the formal | 2574 // ArgumentsAccessStub expects the key in rdx and the formal |
| 2640 // parameter count in rax. | 2575 // parameter count in rax. |
| 2641 VisitForAccumulatorValue(args->at(0)); | 2576 VisitForAccumulatorValue(args->at(0)); |
| 2642 __ movq(rdx, rax); | 2577 __ movq(rdx, rax); |
| 2643 __ Move(rax, Smi::FromInt(scope()->num_parameters())); | 2578 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters())); |
| 2644 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 2579 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
| 2645 __ CallStub(&stub); | 2580 __ CallStub(&stub); |
| 2646 context()->Plug(rax); | 2581 context()->Plug(rax); |
| 2647 } | 2582 } |
| 2648 | 2583 |
| 2649 | 2584 |
| 2650 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { | 2585 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { |
| 2651 ASSERT(args->length() == 0); | 2586 ASSERT(args->length() == 0); |
| 2652 | 2587 |
| 2653 Label exit; | 2588 Label exit; |
| 2654 // Get the number of formal parameters. | 2589 // Get the number of formal parameters. |
| 2655 __ Move(rax, Smi::FromInt(scope()->num_parameters())); | 2590 __ Move(rax, Smi::FromInt(info_->scope()->num_parameters())); |
| 2656 | 2591 |
| 2657 // Check if the calling frame is an arguments adaptor frame. | 2592 // Check if the calling frame is an arguments adaptor frame. |
| 2658 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 2593 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 2659 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset), | 2594 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset), |
| 2660 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2595 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2661 __ j(not_equal, &exit, Label::kNear); | 2596 __ j(not_equal, &exit, Label::kNear); |
| 2662 | 2597 |
| 2663 // Arguments adaptor case: Read the arguments length from the | 2598 // Arguments adaptor case: Read the arguments length from the |
| 2664 // adaptor frame. | 2599 // adaptor frame. |
| 2665 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 2600 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2666 | 2601 |
| 2667 __ bind(&exit); | 2602 __ bind(&exit); |
| 2668 if (FLAG_debug_code) __ AbortIfNotSmi(rax); | 2603 if (FLAG_debug_code) __ AbortIfNotSmi(rax); |
| 2669 context()->Plug(rax); | 2604 context()->Plug(rax); |
| 2670 } | 2605 } |
| 2671 | 2606 |
| 2672 | 2607 |
| 2673 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) { | 2608 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) { |
| 2674 ASSERT(args->length() == 1); | 2609 ASSERT(args->length() == 1); |
| 2675 Label done, null, function, non_function_constructor; | 2610 Label done, null, function, non_function_constructor; |
| 2676 | 2611 |
| 2677 VisitForAccumulatorValue(args->at(0)); | 2612 VisitForAccumulatorValue(args->at(0)); |
| 2678 | 2613 |
| 2679 // If the object is a smi, we return null. | 2614 // If the object is a smi, we return null. |
| 2680 __ JumpIfSmi(rax, &null); | 2615 __ JumpIfSmi(rax, &null); |
| 2681 | 2616 |
| 2682 // Check that the object is a JS object but take special care of JS | 2617 // Check that the object is a JS object but take special care of JS |
| 2683 // functions to make sure they have 'Function' as their class. | 2618 // functions to make sure they have 'Function' as their class. |
| 2684 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax); // Map is now in rax. | 2619 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax); |
| 2620 // Map is now in rax. |
| 2685 __ j(below, &null); | 2621 __ j(below, &null); |
| 2686 | 2622 |
| 2687 // As long as JS_FUNCTION_TYPE is the last instance type and it is | 2623 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and |
| 2688 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for | 2624 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after |
| 2689 // LAST_JS_OBJECT_TYPE. | 2625 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. |
| 2690 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 2626 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
| 2691 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1); | 2627 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == |
| 2692 __ CmpInstanceType(rax, JS_FUNCTION_TYPE); | 2628 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); |
| 2693 __ j(equal, &function); | 2629 __ CmpInstanceType(rax, FIRST_CALLABLE_SPEC_OBJECT_TYPE); |
| 2630 __ j(above_equal, &function); |
| 2694 | 2631 |
| 2695 // Check if the constructor in the map is a function. | 2632 // Check if the constructor in the map is a function. |
| 2696 __ movq(rax, FieldOperand(rax, Map::kConstructorOffset)); | 2633 __ movq(rax, FieldOperand(rax, Map::kConstructorOffset)); |
| 2697 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); | 2634 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); |
| 2698 __ j(not_equal, &non_function_constructor); | 2635 __ j(not_equal, &non_function_constructor); |
| 2699 | 2636 |
| 2700 // rax now contains the constructor function. Grab the | 2637 // rax now contains the constructor function. Grab the |
| 2701 // instance class name from there. | 2638 // instance class name from there. |
| 2702 __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset)); | 2639 __ movq(rax, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset)); |
| 2703 __ movq(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset)); | 2640 __ movq(rax, FieldOperand(rax, SharedFunctionInfo::kInstanceClassNameOffset)); |
| (...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3066 | 3003 |
| 3067 int arg_count = args->length() - 2; // 2 ~ receiver and function. | 3004 int arg_count = args->length() - 2; // 2 ~ receiver and function. |
| 3068 for (int i = 0; i < arg_count + 1; i++) { | 3005 for (int i = 0; i < arg_count + 1; i++) { |
| 3069 VisitForStackValue(args->at(i)); | 3006 VisitForStackValue(args->at(i)); |
| 3070 } | 3007 } |
| 3071 VisitForAccumulatorValue(args->last()); // Function. | 3008 VisitForAccumulatorValue(args->last()); // Function. |
| 3072 | 3009 |
| 3073 // InvokeFunction requires the function in rdi. Move it in there. | 3010 // InvokeFunction requires the function in rdi. Move it in there. |
| 3074 __ movq(rdi, result_register()); | 3011 __ movq(rdi, result_register()); |
| 3075 ParameterCount count(arg_count); | 3012 ParameterCount count(arg_count); |
| 3076 __ InvokeFunction(rdi, count, CALL_FUNCTION); | 3013 __ InvokeFunction(rdi, count, CALL_FUNCTION, |
| 3014 NullCallWrapper(), CALL_AS_METHOD); |
| 3077 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 3015 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 3078 context()->Plug(rax); | 3016 context()->Plug(rax); |
| 3079 } | 3017 } |
| 3080 | 3018 |
| 3081 | 3019 |
| 3082 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) { | 3020 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) { |
| 3083 RegExpConstructResultStub stub; | 3021 RegExpConstructResultStub stub; |
| 3084 ASSERT(args->length() == 3); | 3022 ASSERT(args->length() == 3); |
| 3085 VisitForStackValue(args->at(0)); | 3023 VisitForStackValue(args->at(0)); |
| 3086 VisitForStackValue(args->at(1)); | 3024 VisitForStackValue(args->at(1)); |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3342 // other stack fields, and clear the direction flag in anticipation | 3280 // other stack fields, and clear the direction flag in anticipation |
| 3343 // of calling CopyBytes. | 3281 // of calling CopyBytes. |
| 3344 __ subq(rsp, Immediate(2 * kPointerSize)); | 3282 __ subq(rsp, Immediate(2 * kPointerSize)); |
| 3345 __ cld(); | 3283 __ cld(); |
| 3346 // Check that the array is a JSArray | 3284 // Check that the array is a JSArray |
| 3347 __ JumpIfSmi(array, &bailout); | 3285 __ JumpIfSmi(array, &bailout); |
| 3348 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); | 3286 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); |
| 3349 __ j(not_equal, &bailout); | 3287 __ j(not_equal, &bailout); |
| 3350 | 3288 |
| 3351 // Check that the array has fast elements. | 3289 // Check that the array has fast elements. |
| 3352 __ testb(FieldOperand(scratch, Map::kBitField2Offset), | 3290 __ CheckFastElements(scratch, &bailout); |
| 3353 Immediate(1 << Map::kHasFastElements)); | |
| 3354 __ j(zero, &bailout); | |
| 3355 | 3291 |
| 3356 // Array has fast elements, so its length must be a smi. | 3292 // Array has fast elements, so its length must be a smi. |
| 3357 // If the array has length zero, return the empty string. | 3293 // If the array has length zero, return the empty string. |
| 3358 __ movq(array_length, FieldOperand(array, JSArray::kLengthOffset)); | 3294 __ movq(array_length, FieldOperand(array, JSArray::kLengthOffset)); |
| 3359 __ SmiCompare(array_length, Smi::FromInt(0)); | 3295 __ SmiCompare(array_length, Smi::FromInt(0)); |
| 3360 __ j(not_zero, &non_trivial_array); | 3296 __ j(not_zero, &non_trivial_array); |
| 3361 __ LoadRoot(rax, Heap::kEmptyStringRootIndex); | 3297 __ LoadRoot(rax, Heap::kEmptyStringRootIndex); |
| 3362 __ jmp(&return_result); | 3298 __ jmp(&return_result); |
| 3363 | 3299 |
| 3364 // Save the array length on the stack. | 3300 // Save the array length on the stack. |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3590 __ movq(rax, result_operand); | 3526 __ movq(rax, result_operand); |
| 3591 | 3527 |
| 3592 __ bind(&return_result); | 3528 __ bind(&return_result); |
| 3593 // Drop temp values from the stack, and restore context register. | 3529 // Drop temp values from the stack, and restore context register. |
| 3594 __ addq(rsp, Immediate(3 * kPointerSize)); | 3530 __ addq(rsp, Immediate(3 * kPointerSize)); |
| 3595 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 3531 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 3596 context()->Plug(rax); | 3532 context()->Plug(rax); |
| 3597 } | 3533 } |
| 3598 | 3534 |
| 3599 | 3535 |
| 3536 void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>* args) { |
| 3537 ASSERT(args->length() == 1); |
| 3538 |
| 3539 // Load the function into rax. |
| 3540 VisitForAccumulatorValue(args->at(0)); |
| 3541 |
| 3542 // Prepare for the test. |
| 3543 Label materialize_true, materialize_false; |
| 3544 Label* if_true = NULL; |
| 3545 Label* if_false = NULL; |
| 3546 Label* fall_through = NULL; |
| 3547 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3548 &if_true, &if_false, &fall_through); |
| 3549 |
| 3550 // Test for strict mode function. |
| 3551 __ movq(rdx, FieldOperand(rax, JSFunction::kSharedFunctionInfoOffset)); |
| 3552 __ testb(FieldOperand(rdx, SharedFunctionInfo::kStrictModeByteOffset), |
| 3553 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte)); |
| 3554 __ j(not_equal, if_true); |
| 3555 |
| 3556 // Test for native function. |
| 3557 __ testb(FieldOperand(rdx, SharedFunctionInfo::kNativeByteOffset), |
| 3558 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte)); |
| 3559 __ j(not_equal, if_true); |
| 3560 |
| 3561 // Not native or strict-mode function. |
| 3562 __ jmp(if_false); |
| 3563 |
| 3564 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3565 context()->Plug(if_true, if_false); |
| 3566 } |
| 3567 |
| 3568 |
| 3600 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 3569 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 3601 Handle<String> name = expr->name(); | 3570 Handle<String> name = expr->name(); |
| 3602 if (name->length() > 0 && name->Get(0) == '_') { | 3571 if (name->length() > 0 && name->Get(0) == '_') { |
| 3603 Comment cmnt(masm_, "[ InlineRuntimeCall"); | 3572 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
| 3604 EmitInlineRuntimeCall(expr); | 3573 EmitInlineRuntimeCall(expr); |
| 3605 return; | 3574 return; |
| 3606 } | 3575 } |
| 3607 | 3576 |
| 3608 Comment cmnt(masm_, "[ CallRuntime"); | 3577 Comment cmnt(masm_, "[ CallRuntime"); |
| 3609 ZoneList<Expression*>* args = expr->arguments(); | 3578 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3620 VisitForStackValue(args->at(i)); | 3589 VisitForStackValue(args->at(i)); |
| 3621 } | 3590 } |
| 3622 | 3591 |
| 3623 if (expr->is_jsruntime()) { | 3592 if (expr->is_jsruntime()) { |
| 3624 // Call the JS runtime function using a call IC. | 3593 // Call the JS runtime function using a call IC. |
| 3625 __ Move(rcx, expr->name()); | 3594 __ Move(rcx, expr->name()); |
| 3626 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 3595 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 3627 RelocInfo::Mode mode = RelocInfo::CODE_TARGET; | 3596 RelocInfo::Mode mode = RelocInfo::CODE_TARGET; |
| 3628 Handle<Code> ic = | 3597 Handle<Code> ic = |
| 3629 ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); | 3598 ISOLATE->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode); |
| 3630 EmitCallIC(ic, mode, expr->id()); | 3599 __ call(ic, mode, expr->id()); |
| 3631 // Restore context register. | 3600 // Restore context register. |
| 3632 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 3601 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 3633 } else { | 3602 } else { |
| 3634 __ CallRuntime(expr->function(), arg_count); | 3603 __ CallRuntime(expr->function(), arg_count); |
| 3635 } | 3604 } |
| 3636 context()->Plug(rax); | 3605 context()->Plug(rax); |
| 3637 } | 3606 } |
| 3638 | 3607 |
| 3639 | 3608 |
| 3640 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 3609 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3723 } | 3692 } |
| 3724 __ CallRuntime(Runtime::kTypeof, 1); | 3693 __ CallRuntime(Runtime::kTypeof, 1); |
| 3725 context()->Plug(rax); | 3694 context()->Plug(rax); |
| 3726 break; | 3695 break; |
| 3727 } | 3696 } |
| 3728 | 3697 |
| 3729 case Token::ADD: { | 3698 case Token::ADD: { |
| 3730 Comment cmt(masm_, "[ UnaryOperation (ADD)"); | 3699 Comment cmt(masm_, "[ UnaryOperation (ADD)"); |
| 3731 VisitForAccumulatorValue(expr->expression()); | 3700 VisitForAccumulatorValue(expr->expression()); |
| 3732 Label no_conversion; | 3701 Label no_conversion; |
| 3733 Condition is_smi = masm_->CheckSmi(result_register()); | 3702 __ JumpIfSmi(result_register(), &no_conversion); |
| 3734 __ j(is_smi, &no_conversion); | |
| 3735 ToNumberStub convert_stub; | 3703 ToNumberStub convert_stub; |
| 3736 __ CallStub(&convert_stub); | 3704 __ CallStub(&convert_stub); |
| 3737 __ bind(&no_conversion); | 3705 __ bind(&no_conversion); |
| 3738 context()->Plug(result_register()); | 3706 context()->Plug(result_register()); |
| 3739 break; | 3707 break; |
| 3740 } | 3708 } |
| 3741 | 3709 |
| 3742 case Token::SUB: | 3710 case Token::SUB: |
| 3743 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)"); | 3711 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)"); |
| 3744 break; | 3712 break; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 3758 // TODO(svenpanne): Allowing format strings in Comment would be nice here... | 3726 // TODO(svenpanne): Allowing format strings in Comment would be nice here... |
| 3759 Comment cmt(masm_, comment); | 3727 Comment cmt(masm_, comment); |
| 3760 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); | 3728 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); |
| 3761 UnaryOverwriteMode overwrite = | 3729 UnaryOverwriteMode overwrite = |
| 3762 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; | 3730 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; |
| 3763 UnaryOpStub stub(expr->op(), overwrite); | 3731 UnaryOpStub stub(expr->op(), overwrite); |
| 3764 // UnaryOpStub expects the argument to be in the | 3732 // UnaryOpStub expects the argument to be in the |
| 3765 // accumulator register rax. | 3733 // accumulator register rax. |
| 3766 VisitForAccumulatorValue(expr->expression()); | 3734 VisitForAccumulatorValue(expr->expression()); |
| 3767 SetSourcePosition(expr->position()); | 3735 SetSourcePosition(expr->position()); |
| 3768 EmitCallIC(stub.GetCode(), NULL, expr->id()); | 3736 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id()); |
| 3769 context()->Plug(rax); | 3737 context()->Plug(rax); |
| 3770 } | 3738 } |
| 3771 | 3739 |
| 3772 | 3740 |
| 3773 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { | 3741 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { |
| 3774 Comment cmnt(masm_, "[ CountOperation"); | 3742 Comment cmnt(masm_, "[ CountOperation"); |
| 3775 SetSourcePosition(expr->position()); | 3743 SetSourcePosition(expr->position()); |
| 3776 | 3744 |
| 3777 // Invalid left-hand-sides are rewritten to have a 'throw | 3745 // Invalid left-hand-sides are rewritten to have a 'throw |
| 3778 // ReferenceError' as the left-hand side. | 3746 // ReferenceError' as the left-hand side. |
| 3779 if (!expr->expression()->IsValidLeftHandSide()) { | 3747 if (!expr->expression()->IsValidLeftHandSide()) { |
| 3780 VisitForEffect(expr->expression()); | 3748 VisitForEffect(expr->expression()); |
| 3781 return; | 3749 return; |
| 3782 } | 3750 } |
| 3783 | 3751 |
| 3784 // Expression can only be a property, a global or a (parameter or local) | 3752 // Expression can only be a property, a global or a (parameter or local) |
| 3785 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. | 3753 // slot. |
| 3786 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; | 3754 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; |
| 3787 LhsKind assign_type = VARIABLE; | 3755 LhsKind assign_type = VARIABLE; |
| 3788 Property* prop = expr->expression()->AsProperty(); | 3756 Property* prop = expr->expression()->AsProperty(); |
| 3789 // In case of a property we use the uninitialized expression context | 3757 // In case of a property we use the uninitialized expression context |
| 3790 // of the key to detect a named property. | 3758 // of the key to detect a named property. |
| 3791 if (prop != NULL) { | 3759 if (prop != NULL) { |
| 3792 assign_type = | 3760 assign_type = |
| 3793 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; | 3761 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; |
| 3794 } | 3762 } |
| 3795 | 3763 |
| 3796 // Evaluate expression and get value. | 3764 // Evaluate expression and get value. |
| 3797 if (assign_type == VARIABLE) { | 3765 if (assign_type == VARIABLE) { |
| 3798 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); | 3766 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); |
| 3799 AccumulatorValueContext context(this); | 3767 AccumulatorValueContext context(this); |
| 3800 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); | 3768 EmitVariableLoad(expr->expression()->AsVariableProxy()->var()); |
| 3801 } else { | 3769 } else { |
| 3802 // Reserve space for result of postfix operation. | 3770 // Reserve space for result of postfix operation. |
| 3803 if (expr->is_postfix() && !context()->IsEffect()) { | 3771 if (expr->is_postfix() && !context()->IsEffect()) { |
| 3804 __ Push(Smi::FromInt(0)); | 3772 __ Push(Smi::FromInt(0)); |
| 3805 } | 3773 } |
| 3806 if (assign_type == NAMED_PROPERTY) { | 3774 if (assign_type == NAMED_PROPERTY) { |
| 3807 VisitForAccumulatorValue(prop->obj()); | 3775 VisitForAccumulatorValue(prop->obj()); |
| 3808 __ push(rax); // Copy of receiver, needed for later store. | 3776 __ push(rax); // Copy of receiver, needed for later store. |
| 3809 EmitNamedPropertyLoad(prop); | 3777 EmitNamedPropertyLoad(prop); |
| 3810 } else { | 3778 } else { |
| 3811 if (prop->is_arguments_access()) { | 3779 VisitForStackValue(prop->obj()); |
| 3812 VariableProxy* obj_proxy = prop->obj()->AsVariableProxy(); | 3780 VisitForAccumulatorValue(prop->key()); |
| 3813 MemOperand slot_operand = | |
| 3814 EmitSlotSearch(obj_proxy->var()->AsSlot(), rcx); | |
| 3815 __ push(slot_operand); | |
| 3816 __ Move(rax, prop->key()->AsLiteral()->handle()); | |
| 3817 } else { | |
| 3818 VisitForStackValue(prop->obj()); | |
| 3819 VisitForAccumulatorValue(prop->key()); | |
| 3820 } | |
| 3821 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack | 3781 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on stack |
| 3822 __ push(rax); // Copy of key, needed for later store. | 3782 __ push(rax); // Copy of key, needed for later store. |
| 3823 EmitKeyedPropertyLoad(prop); | 3783 EmitKeyedPropertyLoad(prop); |
| 3824 } | 3784 } |
| 3825 } | 3785 } |
| 3826 | 3786 |
| 3827 // We need a second deoptimization point after loading the value | 3787 // We need a second deoptimization point after loading the value |
| 3828 // in case evaluating the property load my have a side effect. | 3788 // in case evaluating the property load my have a side effect. |
| 3829 if (assign_type == VARIABLE) { | 3789 if (assign_type == VARIABLE) { |
| 3830 PrepareForBailout(expr->expression(), TOS_REG); | 3790 PrepareForBailout(expr->expression(), TOS_REG); |
| 3831 } else { | 3791 } else { |
| 3832 PrepareForBailoutForId(expr->CountId(), TOS_REG); | 3792 PrepareForBailoutForId(expr->CountId(), TOS_REG); |
| 3833 } | 3793 } |
| 3834 | 3794 |
| 3835 // Call ToNumber only if operand is not a smi. | 3795 // Call ToNumber only if operand is not a smi. |
| 3836 Label no_conversion; | 3796 Label no_conversion; |
| 3837 Condition is_smi; | 3797 __ JumpIfSmi(rax, &no_conversion, Label::kNear); |
| 3838 is_smi = masm_->CheckSmi(rax); | |
| 3839 __ j(is_smi, &no_conversion, Label::kNear); | |
| 3840 ToNumberStub convert_stub; | 3798 ToNumberStub convert_stub; |
| 3841 __ CallStub(&convert_stub); | 3799 __ CallStub(&convert_stub); |
| 3842 __ bind(&no_conversion); | 3800 __ bind(&no_conversion); |
| 3843 | 3801 |
| 3844 // Save result for postfix expressions. | 3802 // Save result for postfix expressions. |
| 3845 if (expr->is_postfix()) { | 3803 if (expr->is_postfix()) { |
| 3846 if (!context()->IsEffect()) { | 3804 if (!context()->IsEffect()) { |
| 3847 // Save the result on the stack. If we have a named or keyed property | 3805 // Save the result on the stack. If we have a named or keyed property |
| 3848 // we store the result under the receiver that is currently on top | 3806 // we store the result under the receiver that is currently on top |
| 3849 // of the stack. | 3807 // of the stack. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3889 SetSourcePosition(expr->position()); | 3847 SetSourcePosition(expr->position()); |
| 3890 | 3848 |
| 3891 // Call stub for +1/-1. | 3849 // Call stub for +1/-1. |
| 3892 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE); | 3850 BinaryOpStub stub(expr->binary_op(), NO_OVERWRITE); |
| 3893 if (expr->op() == Token::INC) { | 3851 if (expr->op() == Token::INC) { |
| 3894 __ Move(rdx, Smi::FromInt(1)); | 3852 __ Move(rdx, Smi::FromInt(1)); |
| 3895 } else { | 3853 } else { |
| 3896 __ movq(rdx, rax); | 3854 __ movq(rdx, rax); |
| 3897 __ Move(rax, Smi::FromInt(1)); | 3855 __ Move(rax, Smi::FromInt(1)); |
| 3898 } | 3856 } |
| 3899 EmitCallIC(stub.GetCode(), &patch_site, expr->CountId()); | 3857 __ call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId()); |
| 3858 patch_site.EmitPatchInfo(); |
| 3900 __ bind(&done); | 3859 __ bind(&done); |
| 3901 | 3860 |
| 3902 // Store the value returned in rax. | 3861 // Store the value returned in rax. |
| 3903 switch (assign_type) { | 3862 switch (assign_type) { |
| 3904 case VARIABLE: | 3863 case VARIABLE: |
| 3905 if (expr->is_postfix()) { | 3864 if (expr->is_postfix()) { |
| 3906 // Perform the assignment as if via '='. | 3865 // Perform the assignment as if via '='. |
| 3907 { EffectContext context(this); | 3866 { EffectContext context(this); |
| 3908 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3867 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 3909 Token::ASSIGN); | 3868 Token::ASSIGN); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3922 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3881 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3923 context()->Plug(rax); | 3882 context()->Plug(rax); |
| 3924 } | 3883 } |
| 3925 break; | 3884 break; |
| 3926 case NAMED_PROPERTY: { | 3885 case NAMED_PROPERTY: { |
| 3927 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 3886 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 3928 __ pop(rdx); | 3887 __ pop(rdx); |
| 3929 Handle<Code> ic = is_strict_mode() | 3888 Handle<Code> ic = is_strict_mode() |
| 3930 ? isolate()->builtins()->StoreIC_Initialize_Strict() | 3889 ? isolate()->builtins()->StoreIC_Initialize_Strict() |
| 3931 : isolate()->builtins()->StoreIC_Initialize(); | 3890 : isolate()->builtins()->StoreIC_Initialize(); |
| 3932 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 3891 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 3933 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3892 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3934 if (expr->is_postfix()) { | 3893 if (expr->is_postfix()) { |
| 3935 if (!context()->IsEffect()) { | 3894 if (!context()->IsEffect()) { |
| 3936 context()->PlugTOS(); | 3895 context()->PlugTOS(); |
| 3937 } | 3896 } |
| 3938 } else { | 3897 } else { |
| 3939 context()->Plug(rax); | 3898 context()->Plug(rax); |
| 3940 } | 3899 } |
| 3941 break; | 3900 break; |
| 3942 } | 3901 } |
| 3943 case KEYED_PROPERTY: { | 3902 case KEYED_PROPERTY: { |
| 3944 __ pop(rcx); | 3903 __ pop(rcx); |
| 3945 __ pop(rdx); | 3904 __ pop(rdx); |
| 3946 Handle<Code> ic = is_strict_mode() | 3905 Handle<Code> ic = is_strict_mode() |
| 3947 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() | 3906 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict() |
| 3948 : isolate()->builtins()->KeyedStoreIC_Initialize(); | 3907 : isolate()->builtins()->KeyedStoreIC_Initialize(); |
| 3949 EmitCallIC(ic, RelocInfo::CODE_TARGET, expr->id()); | 3908 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 3950 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3909 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3951 if (expr->is_postfix()) { | 3910 if (expr->is_postfix()) { |
| 3952 if (!context()->IsEffect()) { | 3911 if (!context()->IsEffect()) { |
| 3953 context()->PlugTOS(); | 3912 context()->PlugTOS(); |
| 3954 } | 3913 } |
| 3955 } else { | 3914 } else { |
| 3956 context()->Plug(rax); | 3915 context()->Plug(rax); |
| 3957 } | 3916 } |
| 3958 break; | 3917 break; |
| 3959 } | 3918 } |
| 3960 } | 3919 } |
| 3961 } | 3920 } |
| 3962 | 3921 |
| 3963 | 3922 |
| 3964 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 3923 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 3965 VariableProxy* proxy = expr->AsVariableProxy(); | 3924 VariableProxy* proxy = expr->AsVariableProxy(); |
| 3966 ASSERT(!context()->IsEffect()); | 3925 ASSERT(!context()->IsEffect()); |
| 3967 ASSERT(!context()->IsTest()); | 3926 ASSERT(!context()->IsTest()); |
| 3968 | 3927 |
| 3969 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { | 3928 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) { |
| 3970 Comment cmnt(masm_, "Global variable"); | 3929 Comment cmnt(masm_, "Global variable"); |
| 3971 __ Move(rcx, proxy->name()); | 3930 __ Move(rcx, proxy->name()); |
| 3972 __ movq(rax, GlobalObjectOperand()); | 3931 __ movq(rax, GlobalObjectOperand()); |
| 3973 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); | 3932 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); |
| 3974 // Use a regular load, not a contextual load, to avoid a reference | 3933 // Use a regular load, not a contextual load, to avoid a reference |
| 3975 // error. | 3934 // error. |
| 3976 EmitCallIC(ic, RelocInfo::CODE_TARGET, AstNode::kNoNumber); | 3935 __ call(ic); |
| 3977 PrepareForBailout(expr, TOS_REG); | 3936 PrepareForBailout(expr, TOS_REG); |
| 3978 context()->Plug(rax); | 3937 context()->Plug(rax); |
| 3979 } else if (proxy != NULL && | 3938 } else if (proxy != NULL && |
| 3980 proxy->var()->AsSlot() != NULL && | 3939 proxy->var()->AsSlot() != NULL && |
| 3981 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { | 3940 proxy->var()->AsSlot()->type() == Slot::LOOKUP) { |
| 3982 Label done, slow; | 3941 Label done, slow; |
| 3983 | 3942 |
| 3984 // Generate code for loading from variables potentially shadowed | 3943 // Generate code for loading from variables potentially shadowed |
| 3985 // by eval-introduced variables. | 3944 // by eval-introduced variables. |
| 3986 Slot* slot = proxy->var()->AsSlot(); | 3945 Slot* slot = proxy->var()->AsSlot(); |
| 3987 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); | 3946 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done); |
| 3988 | 3947 |
| 3989 __ bind(&slow); | 3948 __ bind(&slow); |
| 3990 __ push(rsi); | 3949 __ push(rsi); |
| 3991 __ Push(proxy->name()); | 3950 __ Push(proxy->name()); |
| 3992 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 3951 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| 3993 PrepareForBailout(expr, TOS_REG); | 3952 PrepareForBailout(expr, TOS_REG); |
| 3994 __ bind(&done); | 3953 __ bind(&done); |
| 3995 | 3954 |
| 3996 context()->Plug(rax); | 3955 context()->Plug(rax); |
| 3997 } else { | 3956 } else { |
| 3998 // This expression cannot throw a reference error at the top level. | 3957 // This expression cannot throw a reference error at the top level. |
| 3999 context()->HandleExpression(expr); | 3958 VisitInCurrentContext(expr); |
| 4000 } | 3959 } |
| 4001 } | 3960 } |
| 4002 | 3961 |
| 4003 | 3962 |
| 4004 bool FullCodeGenerator::TryLiteralCompare(Token::Value op, | 3963 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr, |
| 4005 Expression* left, | 3964 Handle<String> check, |
| 4006 Expression* right, | 3965 Label* if_true, |
| 4007 Label* if_true, | 3966 Label* if_false, |
| 4008 Label* if_false, | 3967 Label* fall_through) { |
| 4009 Label* fall_through) { | |
| 4010 if (op != Token::EQ && op != Token::EQ_STRICT) return false; | |
| 4011 | |
| 4012 // Check for the pattern: typeof <expression> == <string literal>. | |
| 4013 Literal* right_literal = right->AsLiteral(); | |
| 4014 if (right_literal == NULL) return false; | |
| 4015 Handle<Object> right_literal_value = right_literal->handle(); | |
| 4016 if (!right_literal_value->IsString()) return false; | |
| 4017 UnaryOperation* left_unary = left->AsUnaryOperation(); | |
| 4018 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | |
| 4019 Handle<String> check = Handle<String>::cast(right_literal_value); | |
| 4020 | |
| 4021 { AccumulatorValueContext context(this); | 3968 { AccumulatorValueContext context(this); |
| 4022 VisitForTypeofValue(left_unary->expression()); | 3969 VisitForTypeofValue(expr); |
| 4023 } | 3970 } |
| 4024 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3971 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4025 | 3972 |
| 4026 if (check->Equals(isolate()->heap()->number_symbol())) { | 3973 if (check->Equals(isolate()->heap()->number_symbol())) { |
| 4027 __ JumpIfSmi(rax, if_true); | 3974 __ JumpIfSmi(rax, if_true); |
| 4028 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); | 3975 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
| 4029 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); | 3976 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); |
| 4030 Split(equal, if_true, if_false, fall_through); | 3977 Split(equal, if_true, if_false, fall_through); |
| 4031 } else if (check->Equals(isolate()->heap()->string_symbol())) { | 3978 } else if (check->Equals(isolate()->heap()->string_symbol())) { |
| 4032 __ JumpIfSmi(rax, if_false); | 3979 __ JumpIfSmi(rax, if_false); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 4045 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 3992 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 4046 __ j(equal, if_true); | 3993 __ j(equal, if_true); |
| 4047 __ JumpIfSmi(rax, if_false); | 3994 __ JumpIfSmi(rax, if_false); |
| 4048 // Check for undetectable objects => true. | 3995 // Check for undetectable objects => true. |
| 4049 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 3996 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 4050 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), | 3997 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
| 4051 Immediate(1 << Map::kIsUndetectable)); | 3998 Immediate(1 << Map::kIsUndetectable)); |
| 4052 Split(not_zero, if_true, if_false, fall_through); | 3999 Split(not_zero, if_true, if_false, fall_through); |
| 4053 } else if (check->Equals(isolate()->heap()->function_symbol())) { | 4000 } else if (check->Equals(isolate()->heap()->function_symbol())) { |
| 4054 __ JumpIfSmi(rax, if_false); | 4001 __ JumpIfSmi(rax, if_false); |
| 4055 __ CmpObjectType(rax, FIRST_FUNCTION_CLASS_TYPE, rdx); | 4002 STATIC_ASSERT(LAST_CALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE); |
| 4003 __ CmpObjectType(rax, FIRST_CALLABLE_SPEC_OBJECT_TYPE, rdx); |
| 4056 Split(above_equal, if_true, if_false, fall_through); | 4004 Split(above_equal, if_true, if_false, fall_through); |
| 4057 } else if (check->Equals(isolate()->heap()->object_symbol())) { | 4005 } else if (check->Equals(isolate()->heap()->object_symbol())) { |
| 4058 __ JumpIfSmi(rax, if_false); | 4006 __ JumpIfSmi(rax, if_false); |
| 4059 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 4007 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 4060 __ j(equal, if_true); | 4008 __ j(equal, if_true); |
| 4061 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rdx); | 4009 __ CmpObjectType(rax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, rdx); |
| 4062 __ j(below, if_false); | 4010 __ j(below, if_false); |
| 4063 __ CmpInstanceType(rdx, FIRST_FUNCTION_CLASS_TYPE); | 4011 __ CmpInstanceType(rdx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE); |
| 4064 __ j(above_equal, if_false); | 4012 __ j(above, if_false); |
| 4065 // Check for undetectable objects => false. | 4013 // Check for undetectable objects => false. |
| 4066 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), | 4014 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
| 4067 Immediate(1 << Map::kIsUndetectable)); | 4015 Immediate(1 << Map::kIsUndetectable)); |
| 4068 Split(zero, if_true, if_false, fall_through); | 4016 Split(zero, if_true, if_false, fall_through); |
| 4069 } else { | 4017 } else { |
| 4070 if (if_false != fall_through) __ jmp(if_false); | 4018 if (if_false != fall_through) __ jmp(if_false); |
| 4071 } | 4019 } |
| 4072 | |
| 4073 return true; | |
| 4074 } | 4020 } |
| 4075 | 4021 |
| 4076 | 4022 |
| 4023 void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr, |
| 4024 Label* if_true, |
| 4025 Label* if_false, |
| 4026 Label* fall_through) { |
| 4027 VisitForAccumulatorValue(expr); |
| 4028 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4029 |
| 4030 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 4031 Split(equal, if_true, if_false, fall_through); |
| 4032 } |
| 4033 |
| 4034 |
| 4077 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 4035 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| 4078 Comment cmnt(masm_, "[ CompareOperation"); | 4036 Comment cmnt(masm_, "[ CompareOperation"); |
| 4079 SetSourcePosition(expr->position()); | 4037 SetSourcePosition(expr->position()); |
| 4080 | 4038 |
| 4081 // Always perform the comparison for its control flow. Pack the result | 4039 // Always perform the comparison for its control flow. Pack the result |
| 4082 // into the expression's context after the comparison is performed. | 4040 // into the expression's context after the comparison is performed. |
| 4083 Label materialize_true, materialize_false; | 4041 Label materialize_true, materialize_false; |
| 4084 Label* if_true = NULL; | 4042 Label* if_true = NULL; |
| 4085 Label* if_false = NULL; | 4043 Label* if_false = NULL; |
| 4086 Label* fall_through = NULL; | 4044 Label* fall_through = NULL; |
| 4087 context()->PrepareTest(&materialize_true, &materialize_false, | 4045 context()->PrepareTest(&materialize_true, &materialize_false, |
| 4088 &if_true, &if_false, &fall_through); | 4046 &if_true, &if_false, &fall_through); |
| 4089 | 4047 |
| 4090 // First we try a fast inlined version of the compare when one of | 4048 // First we try a fast inlined version of the compare when one of |
| 4091 // the operands is a literal. | 4049 // the operands is a literal. |
| 4092 Token::Value op = expr->op(); | 4050 if (TryLiteralCompare(expr, if_true, if_false, fall_through)) { |
| 4093 Expression* left = expr->left(); | |
| 4094 Expression* right = expr->right(); | |
| 4095 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) { | |
| 4096 context()->Plug(if_true, if_false); | 4051 context()->Plug(if_true, if_false); |
| 4097 return; | 4052 return; |
| 4098 } | 4053 } |
| 4099 | 4054 |
| 4055 Token::Value op = expr->op(); |
| 4100 VisitForStackValue(expr->left()); | 4056 VisitForStackValue(expr->left()); |
| 4101 switch (op) { | 4057 switch (op) { |
| 4102 case Token::IN: | 4058 case Token::IN: |
| 4103 VisitForStackValue(expr->right()); | 4059 VisitForStackValue(expr->right()); |
| 4104 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); | 4060 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); |
| 4105 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); | 4061 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL); |
| 4106 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 4062 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 4107 Split(equal, if_true, if_false, fall_through); | 4063 Split(equal, if_true, if_false, fall_through); |
| 4108 break; | 4064 break; |
| 4109 | 4065 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4164 __ or_(rcx, rax); | 4120 __ or_(rcx, rax); |
| 4165 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear); | 4121 patch_site.EmitJumpIfNotSmi(rcx, &slow_case, Label::kNear); |
| 4166 __ cmpq(rdx, rax); | 4122 __ cmpq(rdx, rax); |
| 4167 Split(cc, if_true, if_false, NULL); | 4123 Split(cc, if_true, if_false, NULL); |
| 4168 __ bind(&slow_case); | 4124 __ bind(&slow_case); |
| 4169 } | 4125 } |
| 4170 | 4126 |
| 4171 // Record position and call the compare IC. | 4127 // Record position and call the compare IC. |
| 4172 SetSourcePosition(expr->position()); | 4128 SetSourcePosition(expr->position()); |
| 4173 Handle<Code> ic = CompareIC::GetUninitialized(op); | 4129 Handle<Code> ic = CompareIC::GetUninitialized(op); |
| 4174 EmitCallIC(ic, &patch_site, expr->id()); | 4130 __ call(ic, RelocInfo::CODE_TARGET, expr->id()); |
| 4131 patch_site.EmitPatchInfo(); |
| 4175 | 4132 |
| 4176 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4133 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4177 __ testq(rax, rax); | 4134 __ testq(rax, rax); |
| 4178 Split(cc, if_true, if_false, fall_through); | 4135 Split(cc, if_true, if_false, fall_through); |
| 4179 } | 4136 } |
| 4180 } | 4137 } |
| 4181 | 4138 |
| 4182 // Convert the result of the comparison into one expected for this | 4139 // Convert the result of the comparison into one expected for this |
| 4183 // expression's context. | 4140 // expression's context. |
| 4184 context()->Plug(if_true, if_false); | 4141 context()->Plug(if_true, if_false); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 4196 | 4153 |
| 4197 VisitForAccumulatorValue(expr->expression()); | 4154 VisitForAccumulatorValue(expr->expression()); |
| 4198 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 4155 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 4199 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 4156 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 4200 if (expr->is_strict()) { | 4157 if (expr->is_strict()) { |
| 4201 Split(equal, if_true, if_false, fall_through); | 4158 Split(equal, if_true, if_false, fall_through); |
| 4202 } else { | 4159 } else { |
| 4203 __ j(equal, if_true); | 4160 __ j(equal, if_true); |
| 4204 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 4161 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 4205 __ j(equal, if_true); | 4162 __ j(equal, if_true); |
| 4206 Condition is_smi = masm_->CheckSmi(rax); | 4163 __ JumpIfSmi(rax, if_false); |
| 4207 __ j(is_smi, if_false); | |
| 4208 // It can be an undetectable object. | 4164 // It can be an undetectable object. |
| 4209 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 4165 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 4210 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), | 4166 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
| 4211 Immediate(1 << Map::kIsUndetectable)); | 4167 Immediate(1 << Map::kIsUndetectable)); |
| 4212 Split(not_zero, if_true, if_false, fall_through); | 4168 Split(not_zero, if_true, if_false, fall_through); |
| 4213 } | 4169 } |
| 4214 context()->Plug(if_true, if_false); | 4170 context()->Plug(if_true, if_false); |
| 4215 } | 4171 } |
| 4216 | 4172 |
| 4217 | 4173 |
| 4218 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 4174 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
| 4219 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 4175 __ movq(rax, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4220 context()->Plug(rax); | 4176 context()->Plug(rax); |
| 4221 } | 4177 } |
| 4222 | 4178 |
| 4223 | 4179 |
| 4224 Register FullCodeGenerator::result_register() { | 4180 Register FullCodeGenerator::result_register() { |
| 4225 return rax; | 4181 return rax; |
| 4226 } | 4182 } |
| 4227 | 4183 |
| 4228 | 4184 |
| 4229 Register FullCodeGenerator::context_register() { | 4185 Register FullCodeGenerator::context_register() { |
| 4230 return rsi; | 4186 return rsi; |
| 4231 } | 4187 } |
| 4232 | 4188 |
| 4233 | 4189 |
| 4234 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, | |
| 4235 RelocInfo::Mode mode, | |
| 4236 unsigned ast_id) { | |
| 4237 ASSERT(mode == RelocInfo::CODE_TARGET || | |
| 4238 mode == RelocInfo::CODE_TARGET_CONTEXT); | |
| 4239 Counters* counters = isolate()->counters(); | |
| 4240 switch (ic->kind()) { | |
| 4241 case Code::LOAD_IC: | |
| 4242 __ IncrementCounter(counters->named_load_full(), 1); | |
| 4243 break; | |
| 4244 case Code::KEYED_LOAD_IC: | |
| 4245 __ IncrementCounter(counters->keyed_load_full(), 1); | |
| 4246 break; | |
| 4247 case Code::STORE_IC: | |
| 4248 __ IncrementCounter(counters->named_store_full(), 1); | |
| 4249 break; | |
| 4250 case Code::KEYED_STORE_IC: | |
| 4251 __ IncrementCounter(counters->keyed_store_full(), 1); | |
| 4252 default: | |
| 4253 break; | |
| 4254 } | |
| 4255 __ call(ic, mode, ast_id); | |
| 4256 } | |
| 4257 | |
| 4258 | |
| 4259 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, | |
| 4260 JumpPatchSite* patch_site, | |
| 4261 unsigned ast_id) { | |
| 4262 Counters* counters = isolate()->counters(); | |
| 4263 switch (ic->kind()) { | |
| 4264 case Code::LOAD_IC: | |
| 4265 __ IncrementCounter(counters->named_load_full(), 1); | |
| 4266 break; | |
| 4267 case Code::KEYED_LOAD_IC: | |
| 4268 __ IncrementCounter(counters->keyed_load_full(), 1); | |
| 4269 break; | |
| 4270 case Code::STORE_IC: | |
| 4271 __ IncrementCounter(counters->named_store_full(), 1); | |
| 4272 break; | |
| 4273 case Code::KEYED_STORE_IC: | |
| 4274 __ IncrementCounter(counters->keyed_store_full(), 1); | |
| 4275 default: | |
| 4276 break; | |
| 4277 } | |
| 4278 __ call(ic, RelocInfo::CODE_TARGET, ast_id); | |
| 4279 if (patch_site != NULL && patch_site->is_bound()) { | |
| 4280 patch_site->EmitPatchInfo(); | |
| 4281 } else { | |
| 4282 __ nop(); // Signals no inlined code. | |
| 4283 } | |
| 4284 } | |
| 4285 | |
| 4286 | |
| 4287 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 4190 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
| 4288 ASSERT(IsAligned(frame_offset, kPointerSize)); | 4191 ASSERT(IsAligned(frame_offset, kPointerSize)); |
| 4289 __ movq(Operand(rbp, frame_offset), value); | 4192 __ movq(Operand(rbp, frame_offset), value); |
| 4290 } | 4193 } |
| 4291 | 4194 |
| 4292 | 4195 |
| 4293 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { | 4196 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { |
| 4294 __ movq(dst, ContextOperand(rsi, context_index)); | 4197 __ movq(dst, ContextOperand(rsi, context_index)); |
| 4295 } | 4198 } |
| 4296 | 4199 |
| 4297 | 4200 |
| 4201 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() { |
| 4202 Scope* declaration_scope = scope()->DeclarationScope(); |
| 4203 if (declaration_scope->is_global_scope()) { |
| 4204 // Contexts nested in the global context have a canonical empty function |
| 4205 // as their closure, not the anonymous closure containing the global |
| 4206 // code. Pass a smi sentinel and let the runtime look up the empty |
| 4207 // function. |
| 4208 __ Push(Smi::FromInt(0)); |
| 4209 } else if (declaration_scope->is_eval_scope()) { |
| 4210 // Contexts created by a call to eval have the same closure as the |
| 4211 // context calling eval, not the anonymous closure containing the eval |
| 4212 // code. Fetch it from the context. |
| 4213 __ push(ContextOperand(rsi, Context::CLOSURE_INDEX)); |
| 4214 } else { |
| 4215 ASSERT(declaration_scope->is_function_scope()); |
| 4216 __ push(Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4217 } |
| 4218 } |
| 4219 |
| 4220 |
| 4298 // ---------------------------------------------------------------------------- | 4221 // ---------------------------------------------------------------------------- |
| 4299 // Non-local control flow support. | 4222 // Non-local control flow support. |
| 4300 | 4223 |
| 4301 | 4224 |
| 4302 void FullCodeGenerator::EnterFinallyBlock() { | 4225 void FullCodeGenerator::EnterFinallyBlock() { |
| 4303 ASSERT(!result_register().is(rdx)); | 4226 ASSERT(!result_register().is(rdx)); |
| 4304 ASSERT(!result_register().is(rcx)); | 4227 ASSERT(!result_register().is(rcx)); |
| 4305 // Cook return address on top of stack (smi encoded Code* delta) | 4228 // Cook return address on top of stack (smi encoded Code* delta) |
| 4306 __ movq(rdx, Operand(rsp, 0)); | 4229 __ pop(rdx); |
| 4307 __ Move(rcx, masm_->CodeObject()); | 4230 __ Move(rcx, masm_->CodeObject()); |
| 4308 __ subq(rdx, rcx); | 4231 __ subq(rdx, rcx); |
| 4309 __ Integer32ToSmi(rdx, rdx); | 4232 __ Integer32ToSmi(rdx, rdx); |
| 4310 __ movq(Operand(rsp, 0), rdx); | 4233 __ push(rdx); |
| 4311 // Store result register while executing finally block. | 4234 // Store result register while executing finally block. |
| 4312 __ push(result_register()); | 4235 __ push(result_register()); |
| 4313 } | 4236 } |
| 4314 | 4237 |
| 4315 | 4238 |
| 4316 void FullCodeGenerator::ExitFinallyBlock() { | 4239 void FullCodeGenerator::ExitFinallyBlock() { |
| 4317 ASSERT(!result_register().is(rdx)); | 4240 ASSERT(!result_register().is(rdx)); |
| 4318 ASSERT(!result_register().is(rcx)); | 4241 ASSERT(!result_register().is(rcx)); |
| 4319 // Restore result register from stack. | |
| 4320 __ pop(result_register()); | 4242 __ pop(result_register()); |
| 4321 // Uncook return address. | 4243 // Uncook return address. |
| 4322 __ movq(rdx, Operand(rsp, 0)); | 4244 __ pop(rdx); |
| 4323 __ SmiToInteger32(rdx, rdx); | 4245 __ SmiToInteger32(rdx, rdx); |
| 4324 __ Move(rcx, masm_->CodeObject()); | 4246 __ Move(rcx, masm_->CodeObject()); |
| 4325 __ addq(rdx, rcx); | 4247 __ addq(rdx, rcx); |
| 4326 __ movq(Operand(rsp, 0), rdx); | 4248 __ jmp(rdx); |
| 4327 // And return. | |
| 4328 __ ret(0); | |
| 4329 } | 4249 } |
| 4330 | 4250 |
| 4331 | 4251 |
| 4332 #undef __ | 4252 #undef __ |
| 4333 | 4253 |
| 4334 | 4254 |
| 4335 } } // namespace v8::internal | 4255 } } // namespace v8::internal |
| 4336 | 4256 |
| 4337 #endif // V8_TARGET_ARCH_X64 | 4257 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |