| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 void LChunkBuilder::Abort(BailoutReason reason) { | 96 void LChunkBuilder::Abort(BailoutReason reason) { |
| 97 info()->set_bailout_reason(reason); | 97 info()->set_bailout_reason(reason); |
| 98 status_ = ABORTED; | 98 status_ = ABORTED; |
| 99 } | 99 } |
| 100 | 100 |
| 101 | 101 |
| 102 #ifdef _MSC_VER | 102 #ifdef _MSC_VER |
| 103 void LCodeGen::MakeSureStackPagesMapped(int offset) { | 103 void LCodeGen::MakeSureStackPagesMapped(int offset) { |
| 104 const int kPageSize = 4 * KB; | 104 const int kPageSize = 4 * KB; |
| 105 for (offset -= kPageSize; offset > 0; offset -= kPageSize) { | 105 for (offset -= kPageSize; offset > 0; offset -= kPageSize) { |
| 106 __ movq(Operand(rsp, offset), rax); | 106 __ movp(Operand(rsp, offset), rax); |
| 107 } | 107 } |
| 108 } | 108 } |
| 109 #endif | 109 #endif |
| 110 | 110 |
| 111 | 111 |
| 112 void LCodeGen::SaveCallerDoubles() { | 112 void LCodeGen::SaveCallerDoubles() { |
| 113 ASSERT(info()->saves_caller_doubles()); | 113 ASSERT(info()->saves_caller_doubles()); |
| 114 ASSERT(NeedsEagerFrame()); | 114 ASSERT(NeedsEagerFrame()); |
| 115 Comment(";;; Save clobbered callee double registers"); | 115 Comment(";;; Save clobbered callee double registers"); |
| 116 int count = 0; | 116 int count = 0; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 } | 154 } |
| 155 #endif | 155 #endif |
| 156 | 156 |
| 157 // Classic mode functions need to replace the receiver with the global proxy | 157 // Classic mode functions need to replace the receiver with the global proxy |
| 158 // when called as functions (without an explicit receiver object). | 158 // when called as functions (without an explicit receiver object). |
| 159 if (info_->this_has_uses() && | 159 if (info_->this_has_uses() && |
| 160 info_->is_classic_mode() && | 160 info_->is_classic_mode() && |
| 161 !info_->is_native()) { | 161 !info_->is_native()) { |
| 162 Label ok; | 162 Label ok; |
| 163 StackArgumentsAccessor args(rsp, scope()->num_parameters()); | 163 StackArgumentsAccessor args(rsp, scope()->num_parameters()); |
| 164 __ movq(rcx, args.GetReceiverOperand()); | 164 __ movp(rcx, args.GetReceiverOperand()); |
| 165 | 165 |
| 166 __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex); | 166 __ CompareRoot(rcx, Heap::kUndefinedValueRootIndex); |
| 167 __ j(not_equal, &ok, Label::kNear); | 167 __ j(not_equal, &ok, Label::kNear); |
| 168 | 168 |
| 169 __ movq(rcx, GlobalObjectOperand()); | 169 __ movp(rcx, GlobalObjectOperand()); |
| 170 __ movq(rcx, FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset)); | 170 __ movp(rcx, FieldOperand(rcx, GlobalObject::kGlobalReceiverOffset)); |
| 171 | 171 |
| 172 __ movq(args.GetReceiverOperand(), rcx); | 172 __ movp(args.GetReceiverOperand(), rcx); |
| 173 | 173 |
| 174 __ bind(&ok); | 174 __ bind(&ok); |
| 175 } | 175 } |
| 176 } | 176 } |
| 177 | 177 |
| 178 info()->set_prologue_offset(masm_->pc_offset()); | 178 info()->set_prologue_offset(masm_->pc_offset()); |
| 179 if (NeedsEagerFrame()) { | 179 if (NeedsEagerFrame()) { |
| 180 ASSERT(!frame_is_built_); | 180 ASSERT(!frame_is_built_); |
| 181 frame_is_built_ = true; | 181 frame_is_built_ = true; |
| 182 __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME); | 182 __ Prologue(info()->IsStub() ? BUILD_STUB_FRAME : BUILD_FUNCTION_FRAME); |
| 183 info()->AddNoFrameRange(0, masm_->pc_offset()); | 183 info()->AddNoFrameRange(0, masm_->pc_offset()); |
| 184 } | 184 } |
| 185 | 185 |
| 186 // Reserve space for the stack slots needed by the code. | 186 // Reserve space for the stack slots needed by the code. |
| 187 int slots = GetStackSlotCount(); | 187 int slots = GetStackSlotCount(); |
| 188 if (slots > 0) { | 188 if (slots > 0) { |
| 189 if (FLAG_debug_code) { | 189 if (FLAG_debug_code) { |
| 190 __ subq(rsp, Immediate(slots * kPointerSize)); | 190 __ subq(rsp, Immediate(slots * kPointerSize)); |
| 191 #ifdef _MSC_VER | 191 #ifdef _MSC_VER |
| 192 MakeSureStackPagesMapped(slots * kPointerSize); | 192 MakeSureStackPagesMapped(slots * kPointerSize); |
| 193 #endif | 193 #endif |
| 194 __ push(rax); | 194 __ push(rax); |
| 195 __ Set(rax, slots); | 195 __ Set(rax, slots); |
| 196 __ movq(kScratchRegister, kSlotsZapValue); | 196 __ movq(kScratchRegister, kSlotsZapValue); |
| 197 Label loop; | 197 Label loop; |
| 198 __ bind(&loop); | 198 __ bind(&loop); |
| 199 __ movq(MemOperand(rsp, rax, times_pointer_size, 0), | 199 __ movp(MemOperand(rsp, rax, times_pointer_size, 0), |
| 200 kScratchRegister); | 200 kScratchRegister); |
| 201 __ decl(rax); | 201 __ decl(rax); |
| 202 __ j(not_zero, &loop); | 202 __ j(not_zero, &loop); |
| 203 __ pop(rax); | 203 __ pop(rax); |
| 204 } else { | 204 } else { |
| 205 __ subq(rsp, Immediate(slots * kPointerSize)); | 205 __ subq(rsp, Immediate(slots * kPointerSize)); |
| 206 #ifdef _MSC_VER | 206 #ifdef _MSC_VER |
| 207 MakeSureStackPagesMapped(slots * kPointerSize); | 207 MakeSureStackPagesMapped(slots * kPointerSize); |
| 208 #endif | 208 #endif |
| 209 } | 209 } |
| 210 | 210 |
| 211 if (info()->saves_caller_doubles()) { | 211 if (info()->saves_caller_doubles()) { |
| 212 SaveCallerDoubles(); | 212 SaveCallerDoubles(); |
| 213 } | 213 } |
| 214 } | 214 } |
| 215 | 215 |
| 216 // Possibly allocate a local context. | 216 // Possibly allocate a local context. |
| 217 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 217 int heap_slots = info_->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 218 if (heap_slots > 0) { | 218 if (heap_slots > 0) { |
| 219 Comment(";;; Allocate local context"); | 219 Comment(";;; Allocate local context"); |
| 220 // Argument to NewContext is the function, which is still in rdi. | 220 // Argument to NewContext is the function, which is still in rdi. |
| 221 __ push(rdi); | |
| 222 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 221 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 223 FastNewContextStub stub(heap_slots); | 222 FastNewContextStub stub(heap_slots); |
| 224 __ CallStub(&stub); | 223 __ CallStub(&stub); |
| 225 } else { | 224 } else { |
| 225 __ push(rdi); |
| 226 __ CallRuntime(Runtime::kNewFunctionContext, 1); | 226 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
| 227 } | 227 } |
| 228 RecordSafepoint(Safepoint::kNoLazyDeopt); | 228 RecordSafepoint(Safepoint::kNoLazyDeopt); |
| 229 // Context is returned in both rax and rsi. It replaces the context | 229 // Context is returned in rax. It replaces the context passed to us. |
| 230 // passed to us. It's saved in the stack and kept live in rsi. | 230 // It's saved in the stack and kept live in rsi. |
| 231 __ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi); | 231 __ movp(rsi, rax); |
| 232 __ movp(Operand(rbp, StandardFrameConstants::kContextOffset), rax); |
| 232 | 233 |
| 233 // Copy any necessary parameters into the context. | 234 // Copy any necessary parameters into the context. |
| 234 int num_parameters = scope()->num_parameters(); | 235 int num_parameters = scope()->num_parameters(); |
| 235 for (int i = 0; i < num_parameters; i++) { | 236 for (int i = 0; i < num_parameters; i++) { |
| 236 Variable* var = scope()->parameter(i); | 237 Variable* var = scope()->parameter(i); |
| 237 if (var->IsContextSlot()) { | 238 if (var->IsContextSlot()) { |
| 238 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 239 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 239 (num_parameters - 1 - i) * kPointerSize; | 240 (num_parameters - 1 - i) * kPointerSize; |
| 240 // Load parameter from stack. | 241 // Load parameter from stack. |
| 241 __ movq(rax, Operand(rbp, parameter_offset)); | 242 __ movp(rax, Operand(rbp, parameter_offset)); |
| 242 // Store it in the context. | 243 // Store it in the context. |
| 243 int context_offset = Context::SlotOffset(var->index()); | 244 int context_offset = Context::SlotOffset(var->index()); |
| 244 __ movq(Operand(rsi, context_offset), rax); | 245 __ movp(Operand(rsi, context_offset), rax); |
| 245 // Update the write barrier. This clobbers rax and rbx. | 246 // Update the write barrier. This clobbers rax and rbx. |
| 246 __ RecordWriteContextSlot(rsi, context_offset, rax, rbx, kSaveFPRegs); | 247 __ RecordWriteContextSlot(rsi, context_offset, rax, rbx, kSaveFPRegs); |
| 247 } | 248 } |
| 248 } | 249 } |
| 249 Comment(";;; End allocate local context"); | 250 Comment(";;; End allocate local context"); |
| 250 } | 251 } |
| 251 | 252 |
| 252 // Trace the call. | 253 // Trace the call. |
| 253 if (FLAG_trace && info()->IsOptimizing()) { | 254 if (FLAG_trace && info()->IsOptimizing()) { |
| 254 __ CallRuntime(Runtime::kTraceEnter, 0); | 255 __ CallRuntime(Runtime::kTraceEnter, 0); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 287 } else { | 288 } else { |
| 288 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); | 289 Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id); |
| 289 } | 290 } |
| 290 if (jump_table_[i].needs_frame) { | 291 if (jump_table_[i].needs_frame) { |
| 291 ASSERT(!info()->saves_caller_doubles()); | 292 ASSERT(!info()->saves_caller_doubles()); |
| 292 __ Move(kScratchRegister, ExternalReference::ForDeoptEntry(entry)); | 293 __ Move(kScratchRegister, ExternalReference::ForDeoptEntry(entry)); |
| 293 if (needs_frame.is_bound()) { | 294 if (needs_frame.is_bound()) { |
| 294 __ jmp(&needs_frame); | 295 __ jmp(&needs_frame); |
| 295 } else { | 296 } else { |
| 296 __ bind(&needs_frame); | 297 __ bind(&needs_frame); |
| 297 __ movq(rsi, MemOperand(rbp, StandardFrameConstants::kContextOffset)); | 298 __ movp(rsi, MemOperand(rbp, StandardFrameConstants::kContextOffset)); |
| 298 __ push(rbp); | 299 __ push(rbp); |
| 299 __ movq(rbp, rsp); | 300 __ movp(rbp, rsp); |
| 300 __ push(rsi); | 301 __ push(rsi); |
| 301 // This variant of deopt can only be used with stubs. Since we don't | 302 // This variant of deopt can only be used with stubs. Since we don't |
| 302 // have a function pointer to install in the stack frame that we're | 303 // have a function pointer to install in the stack frame that we're |
| 303 // building, install a special marker there instead. | 304 // building, install a special marker there instead. |
| 304 ASSERT(info()->IsStub()); | 305 ASSERT(info()->IsStub()); |
| 305 __ Move(rsi, Smi::FromInt(StackFrame::STUB)); | 306 __ Move(rsi, Smi::FromInt(StackFrame::STUB)); |
| 306 __ push(rsi); | 307 __ push(rsi); |
| 307 __ movq(rsi, MemOperand(rsp, kPointerSize)); | 308 __ movp(rsi, MemOperand(rsp, kPointerSize)); |
| 308 __ call(kScratchRegister); | 309 __ call(kScratchRegister); |
| 309 } | 310 } |
| 310 } else { | 311 } else { |
| 311 if (info()->saves_caller_doubles()) { | 312 if (info()->saves_caller_doubles()) { |
| 312 ASSERT(info()->IsStub()); | 313 ASSERT(info()->IsStub()); |
| 313 RestoreCallerDoubles(); | 314 RestoreCallerDoubles(); |
| 314 } | 315 } |
| 315 __ call(entry, RelocInfo::RUNTIME_ENTRY); | 316 __ call(entry, RelocInfo::RUNTIME_ENTRY); |
| 316 } | 317 } |
| 317 } | 318 } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 346 __ Push(Smi::FromInt(StackFrame::STUB)); | 347 __ Push(Smi::FromInt(StackFrame::STUB)); |
| 347 __ lea(rbp, Operand(rsp, 2 * kPointerSize)); | 348 __ lea(rbp, Operand(rsp, 2 * kPointerSize)); |
| 348 Comment(";;; Deferred code"); | 349 Comment(";;; Deferred code"); |
| 349 } | 350 } |
| 350 code->Generate(); | 351 code->Generate(); |
| 351 if (NeedsDeferredFrame()) { | 352 if (NeedsDeferredFrame()) { |
| 352 __ bind(code->done()); | 353 __ bind(code->done()); |
| 353 Comment(";;; Destroy frame"); | 354 Comment(";;; Destroy frame"); |
| 354 ASSERT(frame_is_built_); | 355 ASSERT(frame_is_built_); |
| 355 frame_is_built_ = false; | 356 frame_is_built_ = false; |
| 356 __ movq(rsp, rbp); | 357 __ movp(rsp, rbp); |
| 357 __ pop(rbp); | 358 __ pop(rbp); |
| 358 } | 359 } |
| 359 __ jmp(code->exit()); | 360 __ jmp(code->exit()); |
| 360 } | 361 } |
| 361 } | 362 } |
| 362 | 363 |
| 363 // Deferred code is the last part of the instruction sequence. Mark | 364 // Deferred code is the last part of the instruction sequence. Mark |
| 364 // the generated code as done unless we bailed out. | 365 // the generated code as done unless we bailed out. |
| 365 if (!is_aborted()) status_ = DONE; | 366 if (!is_aborted()) status_ = DONE; |
| 366 return !is_aborted(); | 367 return !is_aborted(); |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 629 | 630 |
| 630 __ CallRuntime(function, num_arguments, save_doubles); | 631 __ CallRuntime(function, num_arguments, save_doubles); |
| 631 | 632 |
| 632 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0); | 633 RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT, 0); |
| 633 } | 634 } |
| 634 | 635 |
| 635 | 636 |
| 636 void LCodeGen::LoadContextFromDeferred(LOperand* context) { | 637 void LCodeGen::LoadContextFromDeferred(LOperand* context) { |
| 637 if (context->IsRegister()) { | 638 if (context->IsRegister()) { |
| 638 if (!ToRegister(context).is(rsi)) { | 639 if (!ToRegister(context).is(rsi)) { |
| 639 __ movq(rsi, ToRegister(context)); | 640 __ movp(rsi, ToRegister(context)); |
| 640 } | 641 } |
| 641 } else if (context->IsStackSlot()) { | 642 } else if (context->IsStackSlot()) { |
| 642 __ movq(rsi, ToOperand(context)); | 643 __ movp(rsi, ToOperand(context)); |
| 643 } else if (context->IsConstantOperand()) { | 644 } else if (context->IsConstantOperand()) { |
| 644 HConstant* constant = | 645 HConstant* constant = |
| 645 chunk_->LookupConstant(LConstantOperand::cast(context)); | 646 chunk_->LookupConstant(LConstantOperand::cast(context)); |
| 646 __ Move(rsi, Handle<Object>::cast(constant->handle(isolate()))); | 647 __ Move(rsi, Handle<Object>::cast(constant->handle(isolate()))); |
| 647 } else { | 648 } else { |
| 648 UNREACHABLE(); | 649 UNREACHABLE(); |
| 649 } | 650 } |
| 650 } | 651 } |
| 651 | 652 |
| 652 | 653 |
| (...skipping 608 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1261 } | 1262 } |
| 1262 } | 1263 } |
| 1263 | 1264 |
| 1264 | 1265 |
| 1265 void LCodeGen::DoMulI(LMulI* instr) { | 1266 void LCodeGen::DoMulI(LMulI* instr) { |
| 1266 Register left = ToRegister(instr->left()); | 1267 Register left = ToRegister(instr->left()); |
| 1267 LOperand* right = instr->right(); | 1268 LOperand* right = instr->right(); |
| 1268 | 1269 |
| 1269 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { | 1270 if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
| 1270 if (instr->hydrogen_value()->representation().IsSmi()) { | 1271 if (instr->hydrogen_value()->representation().IsSmi()) { |
| 1271 __ movq(kScratchRegister, left); | 1272 __ movp(kScratchRegister, left); |
| 1272 } else { | 1273 } else { |
| 1273 __ movl(kScratchRegister, left); | 1274 __ movl(kScratchRegister, left); |
| 1274 } | 1275 } |
| 1275 } | 1276 } |
| 1276 | 1277 |
| 1277 bool can_overflow = | 1278 bool can_overflow = |
| 1278 instr->hydrogen()->CheckFlag(HValue::kCanOverflow); | 1279 instr->hydrogen()->CheckFlag(HValue::kCanOverflow); |
| 1279 if (right->IsConstantOperand()) { | 1280 if (right->IsConstantOperand()) { |
| 1280 int32_t right_value = ToInteger32(LConstantOperand::cast(right)); | 1281 int32_t right_value = ToInteger32(LConstantOperand::cast(right)); |
| 1281 if (right_value == -1) { | 1282 if (right_value == -1) { |
| (...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1576 Register map = ToRegister(instr->value()); | 1577 Register map = ToRegister(instr->value()); |
| 1577 __ EnumLength(result, map); | 1578 __ EnumLength(result, map); |
| 1578 } | 1579 } |
| 1579 | 1580 |
| 1580 | 1581 |
| 1581 void LCodeGen::DoElementsKind(LElementsKind* instr) { | 1582 void LCodeGen::DoElementsKind(LElementsKind* instr) { |
| 1582 Register result = ToRegister(instr->result()); | 1583 Register result = ToRegister(instr->result()); |
| 1583 Register input = ToRegister(instr->value()); | 1584 Register input = ToRegister(instr->value()); |
| 1584 | 1585 |
| 1585 // Load map into |result|. | 1586 // Load map into |result|. |
| 1586 __ movq(result, FieldOperand(input, HeapObject::kMapOffset)); | 1587 __ movp(result, FieldOperand(input, HeapObject::kMapOffset)); |
| 1587 // Load the map's "bit field 2" into |result|. We only need the first byte. | 1588 // Load the map's "bit field 2" into |result|. We only need the first byte. |
| 1588 __ movzxbq(result, FieldOperand(result, Map::kBitField2Offset)); | 1589 __ movzxbq(result, FieldOperand(result, Map::kBitField2Offset)); |
| 1589 // Retrieve elements_kind from bit field 2. | 1590 // Retrieve elements_kind from bit field 2. |
| 1590 __ and_(result, Immediate(Map::kElementsKindMask)); | 1591 __ and_(result, Immediate(Map::kElementsKindMask)); |
| 1591 __ shr(result, Immediate(Map::kElementsKindShift)); | 1592 __ shr(result, Immediate(Map::kElementsKindShift)); |
| 1592 } | 1593 } |
| 1593 | 1594 |
| 1594 | 1595 |
| 1595 void LCodeGen::DoValueOf(LValueOf* instr) { | 1596 void LCodeGen::DoValueOf(LValueOf* instr) { |
| 1596 Register input = ToRegister(instr->value()); | 1597 Register input = ToRegister(instr->value()); |
| 1597 Register result = ToRegister(instr->result()); | 1598 Register result = ToRegister(instr->result()); |
| 1598 ASSERT(input.is(result)); | 1599 ASSERT(input.is(result)); |
| 1599 Label done; | 1600 Label done; |
| 1600 | 1601 |
| 1601 if (!instr->hydrogen()->value()->IsHeapObject()) { | 1602 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 1602 // If the object is a smi return the object. | 1603 // If the object is a smi return the object. |
| 1603 __ JumpIfSmi(input, &done, Label::kNear); | 1604 __ JumpIfSmi(input, &done, Label::kNear); |
| 1604 } | 1605 } |
| 1605 | 1606 |
| 1606 // If the object is not a value type, return the object. | 1607 // If the object is not a value type, return the object. |
| 1607 __ CmpObjectType(input, JS_VALUE_TYPE, kScratchRegister); | 1608 __ CmpObjectType(input, JS_VALUE_TYPE, kScratchRegister); |
| 1608 __ j(not_equal, &done, Label::kNear); | 1609 __ j(not_equal, &done, Label::kNear); |
| 1609 __ movq(result, FieldOperand(input, JSValue::kValueOffset)); | 1610 __ movp(result, FieldOperand(input, JSValue::kValueOffset)); |
| 1610 | 1611 |
| 1611 __ bind(&done); | 1612 __ bind(&done); |
| 1612 } | 1613 } |
| 1613 | 1614 |
| 1614 | 1615 |
| 1615 void LCodeGen::DoDateField(LDateField* instr) { | 1616 void LCodeGen::DoDateField(LDateField* instr) { |
| 1616 Register object = ToRegister(instr->date()); | 1617 Register object = ToRegister(instr->date()); |
| 1617 Register result = ToRegister(instr->result()); | 1618 Register result = ToRegister(instr->result()); |
| 1618 Smi* index = instr->index(); | 1619 Smi* index = instr->index(); |
| 1619 Label runtime, done, not_date_object; | 1620 Label runtime, done, not_date_object; |
| 1620 ASSERT(object.is(result)); | 1621 ASSERT(object.is(result)); |
| 1621 ASSERT(object.is(rax)); | 1622 ASSERT(object.is(rax)); |
| 1622 | 1623 |
| 1623 Condition cc = masm()->CheckSmi(object); | 1624 Condition cc = masm()->CheckSmi(object); |
| 1624 DeoptimizeIf(cc, instr->environment()); | 1625 DeoptimizeIf(cc, instr->environment()); |
| 1625 __ CmpObjectType(object, JS_DATE_TYPE, kScratchRegister); | 1626 __ CmpObjectType(object, JS_DATE_TYPE, kScratchRegister); |
| 1626 DeoptimizeIf(not_equal, instr->environment()); | 1627 DeoptimizeIf(not_equal, instr->environment()); |
| 1627 | 1628 |
| 1628 if (index->value() == 0) { | 1629 if (index->value() == 0) { |
| 1629 __ movq(result, FieldOperand(object, JSDate::kValueOffset)); | 1630 __ movp(result, FieldOperand(object, JSDate::kValueOffset)); |
| 1630 } else { | 1631 } else { |
| 1631 if (index->value() < JSDate::kFirstUncachedField) { | 1632 if (index->value() < JSDate::kFirstUncachedField) { |
| 1632 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); | 1633 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate()); |
| 1633 Operand stamp_operand = __ ExternalOperand(stamp); | 1634 Operand stamp_operand = __ ExternalOperand(stamp); |
| 1634 __ movq(kScratchRegister, stamp_operand); | 1635 __ movp(kScratchRegister, stamp_operand); |
| 1635 __ cmpq(kScratchRegister, FieldOperand(object, | 1636 __ cmpq(kScratchRegister, FieldOperand(object, |
| 1636 JSDate::kCacheStampOffset)); | 1637 JSDate::kCacheStampOffset)); |
| 1637 __ j(not_equal, &runtime, Label::kNear); | 1638 __ j(not_equal, &runtime, Label::kNear); |
| 1638 __ movq(result, FieldOperand(object, JSDate::kValueOffset + | 1639 __ movp(result, FieldOperand(object, JSDate::kValueOffset + |
| 1639 kPointerSize * index->value())); | 1640 kPointerSize * index->value())); |
| 1640 __ jmp(&done, Label::kNear); | 1641 __ jmp(&done, Label::kNear); |
| 1641 } | 1642 } |
| 1642 __ bind(&runtime); | 1643 __ bind(&runtime); |
| 1643 __ PrepareCallCFunction(2); | 1644 __ PrepareCallCFunction(2); |
| 1644 __ movq(arg_reg_1, object); | 1645 __ movp(arg_reg_1, object); |
| 1645 __ Move(arg_reg_2, index, RelocInfo::NONE64); | 1646 __ Move(arg_reg_2, index, RelocInfo::NONE64); |
| 1646 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2); | 1647 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2); |
| 1647 __ bind(&done); | 1648 __ bind(&done); |
| 1648 } | 1649 } |
| 1649 } | 1650 } |
| 1650 | 1651 |
| 1651 | 1652 |
| 1652 Operand LCodeGen::BuildSeqStringOperand(Register string, | 1653 Operand LCodeGen::BuildSeqStringOperand(Register string, |
| 1653 LOperand* index, | 1654 LOperand* index, |
| 1654 String::Encoding encoding) { | 1655 String::Encoding encoding) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1667 } | 1668 } |
| 1668 | 1669 |
| 1669 | 1670 |
| 1670 void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) { | 1671 void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) { |
| 1671 String::Encoding encoding = instr->hydrogen()->encoding(); | 1672 String::Encoding encoding = instr->hydrogen()->encoding(); |
| 1672 Register result = ToRegister(instr->result()); | 1673 Register result = ToRegister(instr->result()); |
| 1673 Register string = ToRegister(instr->string()); | 1674 Register string = ToRegister(instr->string()); |
| 1674 | 1675 |
| 1675 if (FLAG_debug_code) { | 1676 if (FLAG_debug_code) { |
| 1676 __ push(string); | 1677 __ push(string); |
| 1677 __ movq(string, FieldOperand(string, HeapObject::kMapOffset)); | 1678 __ movp(string, FieldOperand(string, HeapObject::kMapOffset)); |
| 1678 __ movzxbq(string, FieldOperand(string, Map::kInstanceTypeOffset)); | 1679 __ movzxbq(string, FieldOperand(string, Map::kInstanceTypeOffset)); |
| 1679 | 1680 |
| 1680 __ andb(string, Immediate(kStringRepresentationMask | kStringEncodingMask)); | 1681 __ andb(string, Immediate(kStringRepresentationMask | kStringEncodingMask)); |
| 1681 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; | 1682 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; |
| 1682 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; | 1683 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; |
| 1683 __ cmpq(string, Immediate(encoding == String::ONE_BYTE_ENCODING | 1684 __ cmpq(string, Immediate(encoding == String::ONE_BYTE_ENCODING |
| 1684 ? one_byte_seq_type : two_byte_seq_type)); | 1685 ? one_byte_seq_type : two_byte_seq_type)); |
| 1685 __ Check(equal, kUnexpectedStringType); | 1686 __ Check(equal, kUnexpectedStringType); |
| 1686 __ pop(string); | 1687 __ pop(string); |
| 1687 } | 1688 } |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1808 Condition condition = (operation == HMathMinMax::kMathMin) | 1809 Condition condition = (operation == HMathMinMax::kMathMin) |
| 1809 ? less_equal | 1810 ? less_equal |
| 1810 : greater_equal; | 1811 : greater_equal; |
| 1811 Register left_reg = ToRegister(left); | 1812 Register left_reg = ToRegister(left); |
| 1812 if (right->IsConstantOperand()) { | 1813 if (right->IsConstantOperand()) { |
| 1813 Immediate right_imm = | 1814 Immediate right_imm = |
| 1814 Immediate(ToInteger32(LConstantOperand::cast(right))); | 1815 Immediate(ToInteger32(LConstantOperand::cast(right))); |
| 1815 ASSERT(!instr->hydrogen_value()->representation().IsSmi()); | 1816 ASSERT(!instr->hydrogen_value()->representation().IsSmi()); |
| 1816 __ cmpl(left_reg, right_imm); | 1817 __ cmpl(left_reg, right_imm); |
| 1817 __ j(condition, &return_left, Label::kNear); | 1818 __ j(condition, &return_left, Label::kNear); |
| 1818 __ movq(left_reg, right_imm); | 1819 __ movp(left_reg, right_imm); |
| 1819 } else if (right->IsRegister()) { | 1820 } else if (right->IsRegister()) { |
| 1820 Register right_reg = ToRegister(right); | 1821 Register right_reg = ToRegister(right); |
| 1821 if (instr->hydrogen_value()->representation().IsSmi()) { | 1822 if (instr->hydrogen_value()->representation().IsSmi()) { |
| 1822 __ cmpq(left_reg, right_reg); | 1823 __ cmpq(left_reg, right_reg); |
| 1823 } else { | 1824 } else { |
| 1824 __ cmpl(left_reg, right_reg); | 1825 __ cmpl(left_reg, right_reg); |
| 1825 } | 1826 } |
| 1826 __ j(condition, &return_left, Label::kNear); | 1827 __ j(condition, &return_left, Label::kNear); |
| 1827 __ movq(left_reg, right_reg); | 1828 __ movp(left_reg, right_reg); |
| 1828 } else { | 1829 } else { |
| 1829 Operand right_op = ToOperand(right); | 1830 Operand right_op = ToOperand(right); |
| 1830 if (instr->hydrogen_value()->representation().IsSmi()) { | 1831 if (instr->hydrogen_value()->representation().IsSmi()) { |
| 1831 __ cmpq(left_reg, right_op); | 1832 __ cmpq(left_reg, right_op); |
| 1832 } else { | 1833 } else { |
| 1833 __ cmpl(left_reg, right_op); | 1834 __ cmpl(left_reg, right_op); |
| 1834 } | 1835 } |
| 1835 __ j(condition, &return_left, Label::kNear); | 1836 __ j(condition, &return_left, Label::kNear); |
| 1836 __ movq(left_reg, right_op); | 1837 __ movp(left_reg, right_op); |
| 1837 } | 1838 } |
| 1838 __ bind(&return_left); | 1839 __ bind(&return_left); |
| 1839 } else { | 1840 } else { |
| 1840 ASSERT(instr->hydrogen()->representation().IsDouble()); | 1841 ASSERT(instr->hydrogen()->representation().IsDouble()); |
| 1841 Label check_nan_left, check_zero, return_left, return_right; | 1842 Label check_nan_left, check_zero, return_left, return_right; |
| 1842 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above; | 1843 Condition condition = (operation == HMathMinMax::kMathMin) ? below : above; |
| 1843 XMMRegister left_reg = ToDoubleRegister(left); | 1844 XMMRegister left_reg = ToDoubleRegister(left); |
| 1844 XMMRegister right_reg = ToDoubleRegister(right); | 1845 XMMRegister right_reg = ToDoubleRegister(right); |
| 1845 __ ucomisd(left_reg, right_reg); | 1846 __ ucomisd(left_reg, right_reg); |
| 1846 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN. | 1847 __ j(parity_even, &check_nan_left, Label::kNear); // At least one NaN. |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2032 __ j(equal, instr->FalseLabel(chunk_)); | 2033 __ j(equal, instr->FalseLabel(chunk_)); |
| 2033 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); | 2034 __ JumpIfSmi(reg, instr->TrueLabel(chunk_)); |
| 2034 } else if (expected.NeedsMap()) { | 2035 } else if (expected.NeedsMap()) { |
| 2035 // If we need a map later and have a Smi -> deopt. | 2036 // If we need a map later and have a Smi -> deopt. |
| 2036 __ testb(reg, Immediate(kSmiTagMask)); | 2037 __ testb(reg, Immediate(kSmiTagMask)); |
| 2037 DeoptimizeIf(zero, instr->environment()); | 2038 DeoptimizeIf(zero, instr->environment()); |
| 2038 } | 2039 } |
| 2039 | 2040 |
| 2040 const Register map = kScratchRegister; | 2041 const Register map = kScratchRegister; |
| 2041 if (expected.NeedsMap()) { | 2042 if (expected.NeedsMap()) { |
| 2042 __ movq(map, FieldOperand(reg, HeapObject::kMapOffset)); | 2043 __ movp(map, FieldOperand(reg, HeapObject::kMapOffset)); |
| 2043 | 2044 |
| 2044 if (expected.CanBeUndetectable()) { | 2045 if (expected.CanBeUndetectable()) { |
| 2045 // Undetectable -> false. | 2046 // Undetectable -> false. |
| 2046 __ testb(FieldOperand(map, Map::kBitFieldOffset), | 2047 __ testb(FieldOperand(map, Map::kBitFieldOffset), |
| 2047 Immediate(1 << Map::kIsUndetectable)); | 2048 Immediate(1 << Map::kIsUndetectable)); |
| 2048 __ j(not_zero, instr->FalseLabel(chunk_)); | 2049 __ j(not_zero, instr->FalseLabel(chunk_)); |
| 2049 } | 2050 } |
| 2050 } | 2051 } |
| 2051 | 2052 |
| 2052 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { | 2053 if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) { |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2266 Condition LCodeGen::EmitIsObject(Register input, | 2267 Condition LCodeGen::EmitIsObject(Register input, |
| 2267 Label* is_not_object, | 2268 Label* is_not_object, |
| 2268 Label* is_object) { | 2269 Label* is_object) { |
| 2269 ASSERT(!input.is(kScratchRegister)); | 2270 ASSERT(!input.is(kScratchRegister)); |
| 2270 | 2271 |
| 2271 __ JumpIfSmi(input, is_not_object); | 2272 __ JumpIfSmi(input, is_not_object); |
| 2272 | 2273 |
| 2273 __ CompareRoot(input, Heap::kNullValueRootIndex); | 2274 __ CompareRoot(input, Heap::kNullValueRootIndex); |
| 2274 __ j(equal, is_object); | 2275 __ j(equal, is_object); |
| 2275 | 2276 |
| 2276 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset)); | 2277 __ movp(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset)); |
| 2277 // Undetectable objects behave like undefined. | 2278 // Undetectable objects behave like undefined. |
| 2278 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), | 2279 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), |
| 2279 Immediate(1 << Map::kIsUndetectable)); | 2280 Immediate(1 << Map::kIsUndetectable)); |
| 2280 __ j(not_zero, is_not_object); | 2281 __ j(not_zero, is_not_object); |
| 2281 | 2282 |
| 2282 __ movzxbl(kScratchRegister, | 2283 __ movzxbl(kScratchRegister, |
| 2283 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); | 2284 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); |
| 2284 __ cmpb(kScratchRegister, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); | 2285 __ cmpb(kScratchRegister, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 2285 __ j(below, is_not_object); | 2286 __ j(below, is_not_object); |
| 2286 __ cmpb(kScratchRegister, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); | 2287 __ cmpb(kScratchRegister, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2340 } | 2341 } |
| 2341 | 2342 |
| 2342 | 2343 |
| 2343 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { | 2344 void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) { |
| 2344 Register input = ToRegister(instr->value()); | 2345 Register input = ToRegister(instr->value()); |
| 2345 Register temp = ToRegister(instr->temp()); | 2346 Register temp = ToRegister(instr->temp()); |
| 2346 | 2347 |
| 2347 if (!instr->hydrogen()->value()->IsHeapObject()) { | 2348 if (!instr->hydrogen()->value()->IsHeapObject()) { |
| 2348 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); | 2349 __ JumpIfSmi(input, instr->FalseLabel(chunk_)); |
| 2349 } | 2350 } |
| 2350 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset)); | 2351 __ movp(temp, FieldOperand(input, HeapObject::kMapOffset)); |
| 2351 __ testb(FieldOperand(temp, Map::kBitFieldOffset), | 2352 __ testb(FieldOperand(temp, Map::kBitFieldOffset), |
| 2352 Immediate(1 << Map::kIsUndetectable)); | 2353 Immediate(1 << Map::kIsUndetectable)); |
| 2353 EmitBranch(instr, not_zero); | 2354 EmitBranch(instr, not_zero); |
| 2354 } | 2355 } |
| 2355 | 2356 |
| 2356 | 2357 |
| 2357 void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { | 2358 void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) { |
| 2358 ASSERT(ToRegister(instr->context()).is(rsi)); | 2359 ASSERT(ToRegister(instr->context()).is(rsi)); |
| 2359 Token::Value op = instr->op(); | 2360 Token::Value op = instr->op(); |
| 2360 | 2361 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2446 LAST_SPEC_OBJECT_TYPE - 1); | 2447 LAST_SPEC_OBJECT_TYPE - 1); |
| 2447 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); | 2448 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); |
| 2448 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp); | 2449 __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp); |
| 2449 __ j(below, is_false); | 2450 __ j(below, is_false); |
| 2450 __ j(equal, is_true); | 2451 __ j(equal, is_true); |
| 2451 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE); | 2452 __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE); |
| 2452 __ j(equal, is_true); | 2453 __ j(equal, is_true); |
| 2453 } else { | 2454 } else { |
| 2454 // Faster code path to avoid two compares: subtract lower bound from the | 2455 // Faster code path to avoid two compares: subtract lower bound from the |
| 2455 // actual type and do a signed compare with the width of the type range. | 2456 // actual type and do a signed compare with the width of the type range. |
| 2456 __ movq(temp, FieldOperand(input, HeapObject::kMapOffset)); | 2457 __ movp(temp, FieldOperand(input, HeapObject::kMapOffset)); |
| 2457 __ movzxbl(temp2, FieldOperand(temp, Map::kInstanceTypeOffset)); | 2458 __ movzxbl(temp2, FieldOperand(temp, Map::kInstanceTypeOffset)); |
| 2458 __ subq(temp2, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); | 2459 __ subq(temp2, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 2459 __ cmpq(temp2, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - | 2460 __ cmpq(temp2, Immediate(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - |
| 2460 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); | 2461 FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
| 2461 __ j(above, is_false); | 2462 __ j(above, is_false); |
| 2462 } | 2463 } |
| 2463 | 2464 |
| 2464 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. | 2465 // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. |
| 2465 // Check if the constructor in the map is a function. | 2466 // Check if the constructor in the map is a function. |
| 2466 __ movq(temp, FieldOperand(temp, Map::kConstructorOffset)); | 2467 __ movp(temp, FieldOperand(temp, Map::kConstructorOffset)); |
| 2467 | 2468 |
| 2468 // Objects with a non-function constructor have class 'Object'. | 2469 // Objects with a non-function constructor have class 'Object'. |
| 2469 __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister); | 2470 __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister); |
| 2470 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) { | 2471 if (class_name->IsOneByteEqualTo(STATIC_ASCII_VECTOR("Object"))) { |
| 2471 __ j(not_equal, is_true); | 2472 __ j(not_equal, is_true); |
| 2472 } else { | 2473 } else { |
| 2473 __ j(not_equal, is_false); | 2474 __ j(not_equal, is_false); |
| 2474 } | 2475 } |
| 2475 | 2476 |
| 2476 // temp now contains the constructor function. Grab the | 2477 // temp now contains the constructor function. Grab the |
| 2477 // instance class name from there. | 2478 // instance class name from there. |
| 2478 __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); | 2479 __ movp(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset)); |
| 2479 __ movq(temp, FieldOperand(temp, | 2480 __ movp(temp, FieldOperand(temp, |
| 2480 SharedFunctionInfo::kInstanceClassNameOffset)); | 2481 SharedFunctionInfo::kInstanceClassNameOffset)); |
| 2481 // The class name we are testing against is internalized since it's a literal. | 2482 // The class name we are testing against is internalized since it's a literal. |
| 2482 // The name in the constructor is internalized because of the way the context | 2483 // The name in the constructor is internalized because of the way the context |
| 2483 // is booted. This routine isn't expected to work for random API-created | 2484 // is booted. This routine isn't expected to work for random API-created |
| 2484 // classes and it doesn't have to because you can't access it with natives | 2485 // classes and it doesn't have to because you can't access it with natives |
| 2485 // syntax. Since both sides are internalized it is sufficient to use an | 2486 // syntax. Since both sides are internalized it is sufficient to use an |
| 2486 // identity comparison. | 2487 // identity comparison. |
| 2487 ASSERT(class_name->IsInternalizedString()); | 2488 ASSERT(class_name->IsInternalizedString()); |
| 2488 __ Cmp(temp, class_name); | 2489 __ Cmp(temp, class_name); |
| 2489 // End with the answer in the z flag. | 2490 // End with the answer in the z flag. |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2553 | 2554 |
| 2554 // A Smi is not an instance of anything. | 2555 // A Smi is not an instance of anything. |
| 2555 __ JumpIfSmi(object, &false_result, Label::kNear); | 2556 __ JumpIfSmi(object, &false_result, Label::kNear); |
| 2556 | 2557 |
| 2557 // This is the inlined call site instanceof cache. The two occurences of the | 2558 // This is the inlined call site instanceof cache. The two occurences of the |
| 2558 // hole value will be patched to the last map/result pair generated by the | 2559 // hole value will be patched to the last map/result pair generated by the |
| 2559 // instanceof stub. | 2560 // instanceof stub. |
| 2560 Label cache_miss; | 2561 Label cache_miss; |
| 2561 // Use a temp register to avoid memory operands with variable lengths. | 2562 // Use a temp register to avoid memory operands with variable lengths. |
| 2562 Register map = ToRegister(instr->temp()); | 2563 Register map = ToRegister(instr->temp()); |
| 2563 __ movq(map, FieldOperand(object, HeapObject::kMapOffset)); | 2564 __ movp(map, FieldOperand(object, HeapObject::kMapOffset)); |
| 2564 __ bind(deferred->map_check()); // Label for calculating code patching. | 2565 __ bind(deferred->map_check()); // Label for calculating code patching. |
| 2565 Handle<Cell> cache_cell = factory()->NewCell(factory()->the_hole_value()); | 2566 Handle<Cell> cache_cell = factory()->NewCell(factory()->the_hole_value()); |
| 2566 __ Move(kScratchRegister, cache_cell, RelocInfo::CELL); | 2567 __ Move(kScratchRegister, cache_cell, RelocInfo::CELL); |
| 2567 __ cmpq(map, Operand(kScratchRegister, 0)); | 2568 __ cmpq(map, Operand(kScratchRegister, 0)); |
| 2568 __ j(not_equal, &cache_miss, Label::kNear); | 2569 __ j(not_equal, &cache_miss, Label::kNear); |
| 2569 // Patched to load either true or false. | 2570 // Patched to load either true or false. |
| 2570 __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex); | 2571 __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex); |
| 2571 #ifdef DEBUG | 2572 #ifdef DEBUG |
| 2572 // Check that the code size between patch label and patch sites is invariant. | 2573 // Check that the code size between patch label and patch sites is invariant. |
| 2573 Label end_of_patched_code; | 2574 Label end_of_patched_code; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2617 CallCodeGeneric(stub.GetCode(isolate()), | 2618 CallCodeGeneric(stub.GetCode(isolate()), |
| 2618 RelocInfo::CODE_TARGET, | 2619 RelocInfo::CODE_TARGET, |
| 2619 instr, | 2620 instr, |
| 2620 RECORD_SAFEPOINT_WITH_REGISTERS, | 2621 RECORD_SAFEPOINT_WITH_REGISTERS, |
| 2621 2); | 2622 2); |
| 2622 ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check)); | 2623 ASSERT(delta == masm_->SizeOfCodeGeneratedSince(map_check)); |
| 2623 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment(); | 2624 LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment(); |
| 2624 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); | 2625 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); |
| 2625 // Move result to a register that survives the end of the | 2626 // Move result to a register that survives the end of the |
| 2626 // PushSafepointRegisterScope. | 2627 // PushSafepointRegisterScope. |
| 2627 __ movq(kScratchRegister, rax); | 2628 __ movp(kScratchRegister, rax); |
| 2628 } | 2629 } |
| 2629 __ testq(kScratchRegister, kScratchRegister); | 2630 __ testq(kScratchRegister, kScratchRegister); |
| 2630 Label load_false; | 2631 Label load_false; |
| 2631 Label done; | 2632 Label done; |
| 2632 __ j(not_zero, &load_false, Label::kNear); | 2633 __ j(not_zero, &load_false, Label::kNear); |
| 2633 __ LoadRoot(rax, Heap::kTrueValueRootIndex); | 2634 __ LoadRoot(rax, Heap::kTrueValueRootIndex); |
| 2634 __ jmp(&done, Label::kNear); | 2635 __ jmp(&done, Label::kNear); |
| 2635 __ bind(&load_false); | 2636 __ bind(&load_false); |
| 2636 __ LoadRoot(rax, Heap::kFalseValueRootIndex); | 2637 __ LoadRoot(rax, Heap::kFalseValueRootIndex); |
| 2637 __ bind(&done); | 2638 __ bind(&done); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2657 } | 2658 } |
| 2658 | 2659 |
| 2659 | 2660 |
| 2660 void LCodeGen::DoReturn(LReturn* instr) { | 2661 void LCodeGen::DoReturn(LReturn* instr) { |
| 2661 if (FLAG_trace && info()->IsOptimizing()) { | 2662 if (FLAG_trace && info()->IsOptimizing()) { |
| 2662 // Preserve the return value on the stack and rely on the runtime call | 2663 // Preserve the return value on the stack and rely on the runtime call |
| 2663 // to return the value in the same register. We're leaving the code | 2664 // to return the value in the same register. We're leaving the code |
| 2664 // managed by the register allocator and tearing down the frame, it's | 2665 // managed by the register allocator and tearing down the frame, it's |
| 2665 // safe to write to the context register. | 2666 // safe to write to the context register. |
| 2666 __ push(rax); | 2667 __ push(rax); |
| 2667 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2668 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 2668 __ CallRuntime(Runtime::kTraceExit, 1); | 2669 __ CallRuntime(Runtime::kTraceExit, 1); |
| 2669 } | 2670 } |
| 2670 if (info()->saves_caller_doubles()) { | 2671 if (info()->saves_caller_doubles()) { |
| 2671 RestoreCallerDoubles(); | 2672 RestoreCallerDoubles(); |
| 2672 } | 2673 } |
| 2673 int no_frame_start = -1; | 2674 int no_frame_start = -1; |
| 2674 if (NeedsEagerFrame()) { | 2675 if (NeedsEagerFrame()) { |
| 2675 __ movq(rsp, rbp); | 2676 __ movp(rsp, rbp); |
| 2676 __ pop(rbp); | 2677 __ pop(rbp); |
| 2677 no_frame_start = masm_->pc_offset(); | 2678 no_frame_start = masm_->pc_offset(); |
| 2678 } | 2679 } |
| 2679 if (instr->has_constant_parameter_count()) { | 2680 if (instr->has_constant_parameter_count()) { |
| 2680 __ Ret((ToInteger32(instr->constant_parameter_count()) + 1) * kPointerSize, | 2681 __ Ret((ToInteger32(instr->constant_parameter_count()) + 1) * kPointerSize, |
| 2681 rcx); | 2682 rcx); |
| 2682 } else { | 2683 } else { |
| 2683 Register reg = ToRegister(instr->parameter_count()); | 2684 Register reg = ToRegister(instr->parameter_count()); |
| 2684 // The argument count parameter is a smi | 2685 // The argument count parameter is a smi |
| 2685 __ SmiToInteger32(reg, reg); | 2686 __ SmiToInteger32(reg, reg); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2726 // to update the property details in the property dictionary to mark | 2727 // to update the property details in the property dictionary to mark |
| 2727 // it as no longer deleted. We deoptimize in that case. | 2728 // it as no longer deleted. We deoptimize in that case. |
| 2728 if (instr->hydrogen()->RequiresHoleCheck()) { | 2729 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2729 // We have a temp because CompareRoot might clobber kScratchRegister. | 2730 // We have a temp because CompareRoot might clobber kScratchRegister. |
| 2730 Register cell = ToRegister(instr->temp()); | 2731 Register cell = ToRegister(instr->temp()); |
| 2731 ASSERT(!value.is(cell)); | 2732 ASSERT(!value.is(cell)); |
| 2732 __ Move(cell, cell_handle, RelocInfo::CELL); | 2733 __ Move(cell, cell_handle, RelocInfo::CELL); |
| 2733 __ CompareRoot(Operand(cell, 0), Heap::kTheHoleValueRootIndex); | 2734 __ CompareRoot(Operand(cell, 0), Heap::kTheHoleValueRootIndex); |
| 2734 DeoptimizeIf(equal, instr->environment()); | 2735 DeoptimizeIf(equal, instr->environment()); |
| 2735 // Store the value. | 2736 // Store the value. |
| 2736 __ movq(Operand(cell, 0), value); | 2737 __ movp(Operand(cell, 0), value); |
| 2737 } else { | 2738 } else { |
| 2738 // Store the value. | 2739 // Store the value. |
| 2739 __ Move(kScratchRegister, cell_handle, RelocInfo::CELL); | 2740 __ Move(kScratchRegister, cell_handle, RelocInfo::CELL); |
| 2740 __ movq(Operand(kScratchRegister, 0), value); | 2741 __ movp(Operand(kScratchRegister, 0), value); |
| 2741 } | 2742 } |
| 2742 // Cells are always rescanned, so no write barrier here. | 2743 // Cells are always rescanned, so no write barrier here. |
| 2743 } | 2744 } |
| 2744 | 2745 |
| 2745 | 2746 |
| 2746 void LCodeGen::DoStoreGlobalGeneric(LStoreGlobalGeneric* instr) { | |
| 2747 ASSERT(ToRegister(instr->context()).is(rsi)); | |
| 2748 ASSERT(ToRegister(instr->global_object()).is(rdx)); | |
| 2749 ASSERT(ToRegister(instr->value()).is(rax)); | |
| 2750 | |
| 2751 __ Move(rcx, instr->name()); | |
| 2752 Handle<Code> ic = StoreIC::initialize_stub(isolate(), | |
| 2753 instr->strict_mode_flag(), | |
| 2754 CONTEXTUAL); | |
| 2755 CallCode(ic, RelocInfo::CODE_TARGET, instr); | |
| 2756 } | |
| 2757 | |
| 2758 | |
| 2759 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { | 2747 void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) { |
| 2760 Register context = ToRegister(instr->context()); | 2748 Register context = ToRegister(instr->context()); |
| 2761 Register result = ToRegister(instr->result()); | 2749 Register result = ToRegister(instr->result()); |
| 2762 __ movq(result, ContextOperand(context, instr->slot_index())); | 2750 __ movp(result, ContextOperand(context, instr->slot_index())); |
| 2763 if (instr->hydrogen()->RequiresHoleCheck()) { | 2751 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2764 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); | 2752 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
| 2765 if (instr->hydrogen()->DeoptimizesOnHole()) { | 2753 if (instr->hydrogen()->DeoptimizesOnHole()) { |
| 2766 DeoptimizeIf(equal, instr->environment()); | 2754 DeoptimizeIf(equal, instr->environment()); |
| 2767 } else { | 2755 } else { |
| 2768 Label is_not_hole; | 2756 Label is_not_hole; |
| 2769 __ j(not_equal, &is_not_hole, Label::kNear); | 2757 __ j(not_equal, &is_not_hole, Label::kNear); |
| 2770 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); | 2758 __ LoadRoot(result, Heap::kUndefinedValueRootIndex); |
| 2771 __ bind(&is_not_hole); | 2759 __ bind(&is_not_hole); |
| 2772 } | 2760 } |
| 2773 } | 2761 } |
| 2774 } | 2762 } |
| 2775 | 2763 |
| 2776 | 2764 |
| 2777 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { | 2765 void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) { |
| 2778 Register context = ToRegister(instr->context()); | 2766 Register context = ToRegister(instr->context()); |
| 2779 Register value = ToRegister(instr->value()); | 2767 Register value = ToRegister(instr->value()); |
| 2780 | 2768 |
| 2781 Operand target = ContextOperand(context, instr->slot_index()); | 2769 Operand target = ContextOperand(context, instr->slot_index()); |
| 2782 | 2770 |
| 2783 Label skip_assignment; | 2771 Label skip_assignment; |
| 2784 if (instr->hydrogen()->RequiresHoleCheck()) { | 2772 if (instr->hydrogen()->RequiresHoleCheck()) { |
| 2785 __ CompareRoot(target, Heap::kTheHoleValueRootIndex); | 2773 __ CompareRoot(target, Heap::kTheHoleValueRootIndex); |
| 2786 if (instr->hydrogen()->DeoptimizesOnHole()) { | 2774 if (instr->hydrogen()->DeoptimizesOnHole()) { |
| 2787 DeoptimizeIf(equal, instr->environment()); | 2775 DeoptimizeIf(equal, instr->environment()); |
| 2788 } else { | 2776 } else { |
| 2789 __ j(not_equal, &skip_assignment); | 2777 __ j(not_equal, &skip_assignment); |
| 2790 } | 2778 } |
| 2791 } | 2779 } |
| 2792 __ movq(target, value); | 2780 __ movp(target, value); |
| 2793 | 2781 |
| 2794 if (instr->hydrogen()->NeedsWriteBarrier()) { | 2782 if (instr->hydrogen()->NeedsWriteBarrier()) { |
| 2795 SmiCheck check_needed = | 2783 SmiCheck check_needed = |
| 2796 instr->hydrogen()->value()->IsHeapObject() | 2784 instr->hydrogen()->value()->IsHeapObject() |
| 2797 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 2785 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 2798 int offset = Context::SlotOffset(instr->slot_index()); | 2786 int offset = Context::SlotOffset(instr->slot_index()); |
| 2799 Register scratch = ToRegister(instr->temp()); | 2787 Register scratch = ToRegister(instr->temp()); |
| 2800 __ RecordWriteContextSlot(context, | 2788 __ RecordWriteContextSlot(context, |
| 2801 offset, | 2789 offset, |
| 2802 value, | 2790 value, |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2829 Register object = ToRegister(instr->object()); | 2817 Register object = ToRegister(instr->object()); |
| 2830 if (FLAG_track_double_fields && | 2818 if (FLAG_track_double_fields && |
| 2831 instr->hydrogen()->representation().IsDouble()) { | 2819 instr->hydrogen()->representation().IsDouble()) { |
| 2832 XMMRegister result = ToDoubleRegister(instr->result()); | 2820 XMMRegister result = ToDoubleRegister(instr->result()); |
| 2833 __ movsd(result, FieldOperand(object, offset)); | 2821 __ movsd(result, FieldOperand(object, offset)); |
| 2834 return; | 2822 return; |
| 2835 } | 2823 } |
| 2836 | 2824 |
| 2837 Register result = ToRegister(instr->result()); | 2825 Register result = ToRegister(instr->result()); |
| 2838 if (!access.IsInobject()) { | 2826 if (!access.IsInobject()) { |
| 2839 __ movq(result, FieldOperand(object, JSObject::kPropertiesOffset)); | 2827 __ movp(result, FieldOperand(object, JSObject::kPropertiesOffset)); |
| 2840 object = result; | 2828 object = result; |
| 2841 } | 2829 } |
| 2842 | 2830 |
| 2843 Representation representation = access.representation(); | 2831 Representation representation = access.representation(); |
| 2844 if (representation.IsSmi() && | 2832 if (representation.IsSmi() && |
| 2845 instr->hydrogen()->representation().IsInteger32()) { | 2833 instr->hydrogen()->representation().IsInteger32()) { |
| 2846 // Read int value directly from upper half of the smi. | 2834 // Read int value directly from upper half of the smi. |
| 2847 STATIC_ASSERT(kSmiTag == 0); | 2835 STATIC_ASSERT(kSmiTag == 0); |
| 2848 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32); | 2836 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32); |
| 2849 offset += kPointerSize / 2; | 2837 offset += kPointerSize / 2; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2872 __ CmpObjectType(function, JS_FUNCTION_TYPE, result); | 2860 __ CmpObjectType(function, JS_FUNCTION_TYPE, result); |
| 2873 DeoptimizeIf(not_equal, instr->environment()); | 2861 DeoptimizeIf(not_equal, instr->environment()); |
| 2874 | 2862 |
| 2875 // Check whether the function has an instance prototype. | 2863 // Check whether the function has an instance prototype. |
| 2876 Label non_instance; | 2864 Label non_instance; |
| 2877 __ testb(FieldOperand(result, Map::kBitFieldOffset), | 2865 __ testb(FieldOperand(result, Map::kBitFieldOffset), |
| 2878 Immediate(1 << Map::kHasNonInstancePrototype)); | 2866 Immediate(1 << Map::kHasNonInstancePrototype)); |
| 2879 __ j(not_zero, &non_instance, Label::kNear); | 2867 __ j(not_zero, &non_instance, Label::kNear); |
| 2880 | 2868 |
| 2881 // Get the prototype or initial map from the function. | 2869 // Get the prototype or initial map from the function. |
| 2882 __ movq(result, | 2870 __ movp(result, |
| 2883 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); | 2871 FieldOperand(function, JSFunction::kPrototypeOrInitialMapOffset)); |
| 2884 | 2872 |
| 2885 // Check that the function has a prototype or an initial map. | 2873 // Check that the function has a prototype or an initial map. |
| 2886 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); | 2874 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
| 2887 DeoptimizeIf(equal, instr->environment()); | 2875 DeoptimizeIf(equal, instr->environment()); |
| 2888 | 2876 |
| 2889 // If the function does not have an initial map, we're done. | 2877 // If the function does not have an initial map, we're done. |
| 2890 Label done; | 2878 Label done; |
| 2891 __ CmpObjectType(result, MAP_TYPE, kScratchRegister); | 2879 __ CmpObjectType(result, MAP_TYPE, kScratchRegister); |
| 2892 __ j(not_equal, &done, Label::kNear); | 2880 __ j(not_equal, &done, Label::kNear); |
| 2893 | 2881 |
| 2894 // Get the prototype from the initial map. | 2882 // Get the prototype from the initial map. |
| 2895 __ movq(result, FieldOperand(result, Map::kPrototypeOffset)); | 2883 __ movp(result, FieldOperand(result, Map::kPrototypeOffset)); |
| 2896 __ jmp(&done, Label::kNear); | 2884 __ jmp(&done, Label::kNear); |
| 2897 | 2885 |
| 2898 // Non-instance prototype: Fetch prototype from constructor field | 2886 // Non-instance prototype: Fetch prototype from constructor field |
| 2899 // in the function's map. | 2887 // in the function's map. |
| 2900 __ bind(&non_instance); | 2888 __ bind(&non_instance); |
| 2901 __ movq(result, FieldOperand(result, Map::kConstructorOffset)); | 2889 __ movp(result, FieldOperand(result, Map::kConstructorOffset)); |
| 2902 | 2890 |
| 2903 // All done. | 2891 // All done. |
| 2904 __ bind(&done); | 2892 __ bind(&done); |
| 2905 } | 2893 } |
| 2906 | 2894 |
| 2907 | 2895 |
| 2908 void LCodeGen::DoLoadRoot(LLoadRoot* instr) { | 2896 void LCodeGen::DoLoadRoot(LLoadRoot* instr) { |
| 2909 Register result = ToRegister(instr->result()); | 2897 Register result = ToRegister(instr->result()); |
| 2910 __ LoadRoot(result, instr->index()); | 2898 __ LoadRoot(result, instr->index()); |
| 2911 } | 2899 } |
| 2912 | 2900 |
| 2913 | 2901 |
| 2914 void LCodeGen::DoLoadExternalArrayPointer( | 2902 void LCodeGen::DoLoadExternalArrayPointer( |
| 2915 LLoadExternalArrayPointer* instr) { | 2903 LLoadExternalArrayPointer* instr) { |
| 2916 Register result = ToRegister(instr->result()); | 2904 Register result = ToRegister(instr->result()); |
| 2917 Register input = ToRegister(instr->object()); | 2905 Register input = ToRegister(instr->object()); |
| 2918 __ movq(result, FieldOperand(input, | 2906 __ movp(result, FieldOperand(input, |
| 2919 ExternalPixelArray::kExternalPointerOffset)); | 2907 ExternalPixelArray::kExternalPointerOffset)); |
| 2920 } | 2908 } |
| 2921 | 2909 |
| 2922 | 2910 |
| 2923 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { | 2911 void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) { |
| 2924 Register arguments = ToRegister(instr->arguments()); | 2912 Register arguments = ToRegister(instr->arguments()); |
| 2925 Register result = ToRegister(instr->result()); | 2913 Register result = ToRegister(instr->result()); |
| 2926 | 2914 |
| 2927 if (instr->length()->IsConstantOperand() && | 2915 if (instr->length()->IsConstantOperand() && |
| 2928 instr->index()->IsConstantOperand()) { | 2916 instr->index()->IsConstantOperand()) { |
| 2929 int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index())); | 2917 int32_t const_index = ToInteger32(LConstantOperand::cast(instr->index())); |
| 2930 int32_t const_length = ToInteger32(LConstantOperand::cast(instr->length())); | 2918 int32_t const_length = ToInteger32(LConstantOperand::cast(instr->length())); |
| 2931 StackArgumentsAccessor args(arguments, const_length, | 2919 StackArgumentsAccessor args(arguments, const_length, |
| 2932 ARGUMENTS_DONT_CONTAIN_RECEIVER); | 2920 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 2933 __ movq(result, args.GetArgumentOperand(const_index)); | 2921 __ movp(result, args.GetArgumentOperand(const_index)); |
| 2934 } else { | 2922 } else { |
| 2935 Register length = ToRegister(instr->length()); | 2923 Register length = ToRegister(instr->length()); |
| 2936 // There are two words between the frame pointer and the last argument. | 2924 // There are two words between the frame pointer and the last argument. |
| 2937 // Subtracting from length accounts for one of them add one more. | 2925 // Subtracting from length accounts for one of them add one more. |
| 2938 if (instr->index()->IsRegister()) { | 2926 if (instr->index()->IsRegister()) { |
| 2939 __ subl(length, ToRegister(instr->index())); | 2927 __ subl(length, ToRegister(instr->index())); |
| 2940 } else { | 2928 } else { |
| 2941 __ subl(length, ToOperand(instr->index())); | 2929 __ subl(length, ToOperand(instr->index())); |
| 2942 } | 2930 } |
| 2943 StackArgumentsAccessor args(arguments, length, | 2931 StackArgumentsAccessor args(arguments, length, |
| 2944 ARGUMENTS_DONT_CONTAIN_RECEIVER); | 2932 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 2945 __ movq(result, args.GetArgumentOperand(0)); | 2933 __ movp(result, args.GetArgumentOperand(0)); |
| 2946 } | 2934 } |
| 2947 } | 2935 } |
| 2948 | 2936 |
| 2949 | 2937 |
| 2950 void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { | 2938 void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { |
| 2951 ElementsKind elements_kind = instr->elements_kind(); | 2939 ElementsKind elements_kind = instr->elements_kind(); |
| 2952 LOperand* key = instr->key(); | 2940 LOperand* key = instr->key(); |
| 2953 if (!key->IsConstantOperand()) { | 2941 if (!key->IsConstantOperand()) { |
| 2954 Register key_reg = ToRegister(key); | 2942 Register key_reg = ToRegister(key); |
| 2955 // Even though the HLoad/StoreKeyed (in this case) instructions force | 2943 // Even though the HLoad/StoreKeyed (in this case) instructions force |
| 2956 // the input representation for the key to be an integer, the input | 2944 // the input representation for the key to be an integer, the input |
| 2957 // gets replaced during bound check elimination with the index argument | 2945 // gets replaced during bound check elimination with the index argument |
| 2958 // to the bounds check, which can be tagged, so that case must be | 2946 // to the bounds check, which can be tagged, so that case must be |
| 2959 // handled here, too. | 2947 // handled here, too. |
| 2960 if (instr->hydrogen()->IsDehoisted()) { | 2948 if (instr->hydrogen()->IsDehoisted()) { |
| 2961 // Sign extend key because it could be a 32 bit negative value | 2949 // Sign extend key because it could be a 32 bit negative value |
| 2962 // and the dehoisted address computation happens in 64 bits | 2950 // and the dehoisted address computation happens in 64 bits |
| 2963 __ movsxlq(key_reg, key_reg); | 2951 __ movsxlq(key_reg, key_reg); |
| 2964 } | 2952 } |
| 2965 } | 2953 } |
| 2954 int base_offset = instr->is_fixed_typed_array() |
| 2955 ? FixedTypedArrayBase::kDataOffset - kHeapObjectTag |
| 2956 : 0; |
| 2966 Operand operand(BuildFastArrayOperand( | 2957 Operand operand(BuildFastArrayOperand( |
| 2967 instr->elements(), | 2958 instr->elements(), |
| 2968 key, | 2959 key, |
| 2969 elements_kind, | 2960 elements_kind, |
| 2970 0, | 2961 base_offset, |
| 2971 instr->additional_index())); | 2962 instr->additional_index())); |
| 2972 | 2963 |
| 2973 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { | 2964 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || |
| 2965 elements_kind == FLOAT32_ELEMENTS) { |
| 2974 XMMRegister result(ToDoubleRegister(instr->result())); | 2966 XMMRegister result(ToDoubleRegister(instr->result())); |
| 2975 __ movss(result, operand); | 2967 __ movss(result, operand); |
| 2976 __ cvtss2sd(result, result); | 2968 __ cvtss2sd(result, result); |
| 2977 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { | 2969 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS || |
| 2970 elements_kind == FLOAT64_ELEMENTS) { |
| 2978 __ movsd(ToDoubleRegister(instr->result()), operand); | 2971 __ movsd(ToDoubleRegister(instr->result()), operand); |
| 2979 } else { | 2972 } else { |
| 2980 Register result(ToRegister(instr->result())); | 2973 Register result(ToRegister(instr->result())); |
| 2981 switch (elements_kind) { | 2974 switch (elements_kind) { |
| 2982 case EXTERNAL_BYTE_ELEMENTS: | 2975 case EXTERNAL_BYTE_ELEMENTS: |
| 2976 case INT8_ELEMENTS: |
| 2983 __ movsxbq(result, operand); | 2977 __ movsxbq(result, operand); |
| 2984 break; | 2978 break; |
| 2985 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 2979 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 2986 case EXTERNAL_PIXEL_ELEMENTS: | 2980 case EXTERNAL_PIXEL_ELEMENTS: |
| 2981 case UINT8_ELEMENTS: |
| 2982 case UINT8_CLAMPED_ELEMENTS: |
| 2987 __ movzxbq(result, operand); | 2983 __ movzxbq(result, operand); |
| 2988 break; | 2984 break; |
| 2989 case EXTERNAL_SHORT_ELEMENTS: | 2985 case EXTERNAL_SHORT_ELEMENTS: |
| 2986 case INT16_ELEMENTS: |
| 2990 __ movsxwq(result, operand); | 2987 __ movsxwq(result, operand); |
| 2991 break; | 2988 break; |
| 2992 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 2989 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 2990 case UINT16_ELEMENTS: |
| 2993 __ movzxwq(result, operand); | 2991 __ movzxwq(result, operand); |
| 2994 break; | 2992 break; |
| 2995 case EXTERNAL_INT_ELEMENTS: | 2993 case EXTERNAL_INT_ELEMENTS: |
| 2994 case INT32_ELEMENTS: |
| 2996 __ movsxlq(result, operand); | 2995 __ movsxlq(result, operand); |
| 2997 break; | 2996 break; |
| 2998 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 2997 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 2998 case UINT32_ELEMENTS: |
| 2999 __ movl(result, operand); | 2999 __ movl(result, operand); |
| 3000 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { | 3000 if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { |
| 3001 __ testl(result, result); | 3001 __ testl(result, result); |
| 3002 DeoptimizeIf(negative, instr->environment()); | 3002 DeoptimizeIf(negative, instr->environment()); |
| 3003 } | 3003 } |
| 3004 break; | 3004 break; |
| 3005 case EXTERNAL_FLOAT_ELEMENTS: | 3005 case EXTERNAL_FLOAT_ELEMENTS: |
| 3006 case EXTERNAL_DOUBLE_ELEMENTS: | 3006 case EXTERNAL_DOUBLE_ELEMENTS: |
| 3007 case FLOAT32_ELEMENTS: |
| 3008 case FLOAT64_ELEMENTS: |
| 3007 case FAST_ELEMENTS: | 3009 case FAST_ELEMENTS: |
| 3008 case FAST_SMI_ELEMENTS: | 3010 case FAST_SMI_ELEMENTS: |
| 3009 case FAST_DOUBLE_ELEMENTS: | 3011 case FAST_DOUBLE_ELEMENTS: |
| 3010 case FAST_HOLEY_ELEMENTS: | 3012 case FAST_HOLEY_ELEMENTS: |
| 3011 case FAST_HOLEY_SMI_ELEMENTS: | 3013 case FAST_HOLEY_SMI_ELEMENTS: |
| 3012 case FAST_HOLEY_DOUBLE_ELEMENTS: | 3014 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 3013 case DICTIONARY_ELEMENTS: | 3015 case DICTIONARY_ELEMENTS: |
| 3014 case NON_STRICT_ARGUMENTS_ELEMENTS: | 3016 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 3015 UNREACHABLE(); | 3017 UNREACHABLE(); |
| 3016 break; | 3018 break; |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3104 DeoptimizeIf(NegateCondition(smi), instr->environment()); | 3106 DeoptimizeIf(NegateCondition(smi), instr->environment()); |
| 3105 } else { | 3107 } else { |
| 3106 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); | 3108 __ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
| 3107 DeoptimizeIf(equal, instr->environment()); | 3109 DeoptimizeIf(equal, instr->environment()); |
| 3108 } | 3110 } |
| 3109 } | 3111 } |
| 3110 } | 3112 } |
| 3111 | 3113 |
| 3112 | 3114 |
| 3113 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { | 3115 void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { |
| 3114 if (instr->is_external()) { | 3116 if (instr->is_typed_elements()) { |
| 3115 DoLoadKeyedExternalArray(instr); | 3117 DoLoadKeyedExternalArray(instr); |
| 3116 } else if (instr->hydrogen()->representation().IsDouble()) { | 3118 } else if (instr->hydrogen()->representation().IsDouble()) { |
| 3117 DoLoadKeyedFixedDoubleArray(instr); | 3119 DoLoadKeyedFixedDoubleArray(instr); |
| 3118 } else { | 3120 } else { |
| 3119 DoLoadKeyedFixedArray(instr); | 3121 DoLoadKeyedFixedArray(instr); |
| 3120 } | 3122 } |
| 3121 } | 3123 } |
| 3122 | 3124 |
| 3123 | 3125 |
| 3124 Operand LCodeGen::BuildFastArrayOperand( | 3126 Operand LCodeGen::BuildFastArrayOperand( |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3158 | 3160 |
| 3159 | 3161 |
| 3160 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { | 3162 void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) { |
| 3161 Register result = ToRegister(instr->result()); | 3163 Register result = ToRegister(instr->result()); |
| 3162 | 3164 |
| 3163 if (instr->hydrogen()->from_inlined()) { | 3165 if (instr->hydrogen()->from_inlined()) { |
| 3164 __ lea(result, Operand(rsp, -kFPOnStackSize + -kPCOnStackSize)); | 3166 __ lea(result, Operand(rsp, -kFPOnStackSize + -kPCOnStackSize)); |
| 3165 } else { | 3167 } else { |
| 3166 // Check for arguments adapter frame. | 3168 // Check for arguments adapter frame. |
| 3167 Label done, adapted; | 3169 Label done, adapted; |
| 3168 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 3170 __ movp(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 3169 __ Cmp(Operand(result, StandardFrameConstants::kContextOffset), | 3171 __ Cmp(Operand(result, StandardFrameConstants::kContextOffset), |
| 3170 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 3172 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 3171 __ j(equal, &adapted, Label::kNear); | 3173 __ j(equal, &adapted, Label::kNear); |
| 3172 | 3174 |
| 3173 // No arguments adaptor frame. | 3175 // No arguments adaptor frame. |
| 3174 __ movq(result, rbp); | 3176 __ movp(result, rbp); |
| 3175 __ jmp(&done, Label::kNear); | 3177 __ jmp(&done, Label::kNear); |
| 3176 | 3178 |
| 3177 // Arguments adaptor frame present. | 3179 // Arguments adaptor frame present. |
| 3178 __ bind(&adapted); | 3180 __ bind(&adapted); |
| 3179 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 3181 __ movp(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 3180 | 3182 |
| 3181 // Result is the frame pointer for the frame if not adapted and for the real | 3183 // Result is the frame pointer for the frame if not adapted and for the real |
| 3182 // frame below the adaptor frame if adapted. | 3184 // frame below the adaptor frame if adapted. |
| 3183 __ bind(&done); | 3185 __ bind(&done); |
| 3184 } | 3186 } |
| 3185 } | 3187 } |
| 3186 | 3188 |
| 3187 | 3189 |
| 3188 void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { | 3190 void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) { |
| 3189 Register result = ToRegister(instr->result()); | 3191 Register result = ToRegister(instr->result()); |
| 3190 | 3192 |
| 3191 Label done; | 3193 Label done; |
| 3192 | 3194 |
| 3193 // If no arguments adaptor frame the number of arguments is fixed. | 3195 // If no arguments adaptor frame the number of arguments is fixed. |
| 3194 if (instr->elements()->IsRegister()) { | 3196 if (instr->elements()->IsRegister()) { |
| 3195 __ cmpq(rbp, ToRegister(instr->elements())); | 3197 __ cmpq(rbp, ToRegister(instr->elements())); |
| 3196 } else { | 3198 } else { |
| 3197 __ cmpq(rbp, ToOperand(instr->elements())); | 3199 __ cmpq(rbp, ToOperand(instr->elements())); |
| 3198 } | 3200 } |
| 3199 __ movl(result, Immediate(scope()->num_parameters())); | 3201 __ movl(result, Immediate(scope()->num_parameters())); |
| 3200 __ j(equal, &done, Label::kNear); | 3202 __ j(equal, &done, Label::kNear); |
| 3201 | 3203 |
| 3202 // Arguments adaptor frame present. Get argument length from there. | 3204 // Arguments adaptor frame present. Get argument length from there. |
| 3203 __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 3205 __ movp(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 3204 __ SmiToInteger32(result, | 3206 __ SmiToInteger32(result, |
| 3205 Operand(result, | 3207 Operand(result, |
| 3206 ArgumentsAdaptorFrameConstants::kLengthOffset)); | 3208 ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 3207 | 3209 |
| 3208 // Argument length is in result register. | 3210 // Argument length is in result register. |
| 3209 __ bind(&done); | 3211 __ bind(&done); |
| 3210 } | 3212 } |
| 3211 | 3213 |
| 3212 | 3214 |
| 3213 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { | 3215 void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) { |
| 3214 Register receiver = ToRegister(instr->receiver()); | 3216 Register receiver = ToRegister(instr->receiver()); |
| 3215 Register function = ToRegister(instr->function()); | 3217 Register function = ToRegister(instr->function()); |
| 3216 | 3218 |
| 3217 // If the receiver is null or undefined, we have to pass the global | 3219 // If the receiver is null or undefined, we have to pass the global |
| 3218 // object as a receiver to normal functions. Values have to be | 3220 // object as a receiver to normal functions. Values have to be |
| 3219 // passed unchanged to builtins and strict-mode functions. | 3221 // passed unchanged to builtins and strict-mode functions. |
| 3220 Label global_object, receiver_ok; | 3222 Label global_object, receiver_ok; |
| 3221 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear; | 3223 Label::Distance dist = DeoptEveryNTimes() ? Label::kFar : Label::kNear; |
| 3222 | 3224 |
| 3223 // Do not transform the receiver to object for strict mode | 3225 // Do not transform the receiver to object for strict mode |
| 3224 // functions. | 3226 // functions. |
| 3225 __ movq(kScratchRegister, | 3227 __ movp(kScratchRegister, |
| 3226 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); | 3228 FieldOperand(function, JSFunction::kSharedFunctionInfoOffset)); |
| 3227 __ testb(FieldOperand(kScratchRegister, | 3229 __ testb(FieldOperand(kScratchRegister, |
| 3228 SharedFunctionInfo::kStrictModeByteOffset), | 3230 SharedFunctionInfo::kStrictModeByteOffset), |
| 3229 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte)); | 3231 Immediate(1 << SharedFunctionInfo::kStrictModeBitWithinByte)); |
| 3230 __ j(not_equal, &receiver_ok, dist); | 3232 __ j(not_equal, &receiver_ok, dist); |
| 3231 | 3233 |
| 3232 // Do not transform the receiver to object for builtins. | 3234 // Do not transform the receiver to object for builtins. |
| 3233 __ testb(FieldOperand(kScratchRegister, | 3235 __ testb(FieldOperand(kScratchRegister, |
| 3234 SharedFunctionInfo::kNativeByteOffset), | 3236 SharedFunctionInfo::kNativeByteOffset), |
| 3235 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte)); | 3237 Immediate(1 << SharedFunctionInfo::kNativeBitWithinByte)); |
| 3236 __ j(not_equal, &receiver_ok, dist); | 3238 __ j(not_equal, &receiver_ok, dist); |
| 3237 | 3239 |
| 3238 // Normal function. Replace undefined or null with global receiver. | 3240 // Normal function. Replace undefined or null with global receiver. |
| 3239 __ CompareRoot(receiver, Heap::kNullValueRootIndex); | 3241 __ CompareRoot(receiver, Heap::kNullValueRootIndex); |
| 3240 __ j(equal, &global_object, Label::kNear); | 3242 __ j(equal, &global_object, Label::kNear); |
| 3241 __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex); | 3243 __ CompareRoot(receiver, Heap::kUndefinedValueRootIndex); |
| 3242 __ j(equal, &global_object, Label::kNear); | 3244 __ j(equal, &global_object, Label::kNear); |
| 3243 | 3245 |
| 3244 // The receiver should be a JS object. | 3246 // The receiver should be a JS object. |
| 3245 Condition is_smi = __ CheckSmi(receiver); | 3247 Condition is_smi = __ CheckSmi(receiver); |
| 3246 DeoptimizeIf(is_smi, instr->environment()); | 3248 DeoptimizeIf(is_smi, instr->environment()); |
| 3247 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, kScratchRegister); | 3249 __ CmpObjectType(receiver, FIRST_SPEC_OBJECT_TYPE, kScratchRegister); |
| 3248 DeoptimizeIf(below, instr->environment()); | 3250 DeoptimizeIf(below, instr->environment()); |
| 3249 __ jmp(&receiver_ok, Label::kNear); | 3251 __ jmp(&receiver_ok, Label::kNear); |
| 3250 | 3252 |
| 3251 __ bind(&global_object); | 3253 __ bind(&global_object); |
| 3252 __ movq(receiver, FieldOperand(function, JSFunction::kContextOffset)); | 3254 __ movp(receiver, FieldOperand(function, JSFunction::kContextOffset)); |
| 3253 __ movq(receiver, | 3255 __ movp(receiver, |
| 3254 Operand(receiver, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | 3256 Operand(receiver, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
| 3255 __ movq(receiver, | 3257 __ movp(receiver, |
| 3256 FieldOperand(receiver, GlobalObject::kGlobalReceiverOffset)); | 3258 FieldOperand(receiver, GlobalObject::kGlobalReceiverOffset)); |
| 3257 __ bind(&receiver_ok); | 3259 __ bind(&receiver_ok); |
| 3258 } | 3260 } |
| 3259 | 3261 |
| 3260 | 3262 |
| 3261 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { | 3263 void LCodeGen::DoApplyArguments(LApplyArguments* instr) { |
| 3262 Register receiver = ToRegister(instr->receiver()); | 3264 Register receiver = ToRegister(instr->receiver()); |
| 3263 Register function = ToRegister(instr->function()); | 3265 Register function = ToRegister(instr->function()); |
| 3264 Register length = ToRegister(instr->length()); | 3266 Register length = ToRegister(instr->length()); |
| 3265 Register elements = ToRegister(instr->elements()); | 3267 Register elements = ToRegister(instr->elements()); |
| 3266 ASSERT(receiver.is(rax)); // Used for parameter count. | 3268 ASSERT(receiver.is(rax)); // Used for parameter count. |
| 3267 ASSERT(function.is(rdi)); // Required by InvokeFunction. | 3269 ASSERT(function.is(rdi)); // Required by InvokeFunction. |
| 3268 ASSERT(ToRegister(instr->result()).is(rax)); | 3270 ASSERT(ToRegister(instr->result()).is(rax)); |
| 3269 | 3271 |
| 3270 // Copy the arguments to this function possibly from the | 3272 // Copy the arguments to this function possibly from the |
| 3271 // adaptor frame below it. | 3273 // adaptor frame below it. |
| 3272 const uint32_t kArgumentsLimit = 1 * KB; | 3274 const uint32_t kArgumentsLimit = 1 * KB; |
| 3273 __ cmpq(length, Immediate(kArgumentsLimit)); | 3275 __ cmpq(length, Immediate(kArgumentsLimit)); |
| 3274 DeoptimizeIf(above, instr->environment()); | 3276 DeoptimizeIf(above, instr->environment()); |
| 3275 | 3277 |
| 3276 __ push(receiver); | 3278 __ push(receiver); |
| 3277 __ movq(receiver, length); | 3279 __ movp(receiver, length); |
| 3278 | 3280 |
| 3279 // Loop through the arguments pushing them onto the execution | 3281 // Loop through the arguments pushing them onto the execution |
| 3280 // stack. | 3282 // stack. |
| 3281 Label invoke, loop; | 3283 Label invoke, loop; |
| 3282 // length is a small non-negative integer, due to the test above. | 3284 // length is a small non-negative integer, due to the test above. |
| 3283 __ testl(length, length); | 3285 __ testl(length, length); |
| 3284 __ j(zero, &invoke, Label::kNear); | 3286 __ j(zero, &invoke, Label::kNear); |
| 3285 __ bind(&loop); | 3287 __ bind(&loop); |
| 3286 StackArgumentsAccessor args(elements, length, | 3288 StackArgumentsAccessor args(elements, length, |
| 3287 ARGUMENTS_DONT_CONTAIN_RECEIVER); | 3289 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 3306 } | 3308 } |
| 3307 | 3309 |
| 3308 | 3310 |
| 3309 void LCodeGen::DoDrop(LDrop* instr) { | 3311 void LCodeGen::DoDrop(LDrop* instr) { |
| 3310 __ Drop(instr->count()); | 3312 __ Drop(instr->count()); |
| 3311 } | 3313 } |
| 3312 | 3314 |
| 3313 | 3315 |
| 3314 void LCodeGen::DoThisFunction(LThisFunction* instr) { | 3316 void LCodeGen::DoThisFunction(LThisFunction* instr) { |
| 3315 Register result = ToRegister(instr->result()); | 3317 Register result = ToRegister(instr->result()); |
| 3316 __ movq(result, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); | 3318 __ movp(result, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset)); |
| 3317 } | 3319 } |
| 3318 | 3320 |
| 3319 | 3321 |
| 3320 void LCodeGen::DoContext(LContext* instr) { | 3322 void LCodeGen::DoContext(LContext* instr) { |
| 3321 Register result = ToRegister(instr->result()); | 3323 Register result = ToRegister(instr->result()); |
| 3322 if (info()->IsOptimizing()) { | 3324 if (info()->IsOptimizing()) { |
| 3323 __ movq(result, Operand(rbp, StandardFrameConstants::kContextOffset)); | 3325 __ movp(result, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 3324 } else { | 3326 } else { |
| 3325 // If there is no frame, the context must be in rsi. | 3327 // If there is no frame, the context must be in rsi. |
| 3326 ASSERT(result.is(rsi)); | 3328 ASSERT(result.is(rsi)); |
| 3327 } | 3329 } |
| 3328 } | 3330 } |
| 3329 | 3331 |
| 3330 | 3332 |
| 3331 void LCodeGen::DoOuterContext(LOuterContext* instr) { | 3333 void LCodeGen::DoOuterContext(LOuterContext* instr) { |
| 3332 Register context = ToRegister(instr->context()); | 3334 Register context = ToRegister(instr->context()); |
| 3333 Register result = ToRegister(instr->result()); | 3335 Register result = ToRegister(instr->result()); |
| 3334 __ movq(result, | 3336 __ movp(result, |
| 3335 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX))); | 3337 Operand(context, Context::SlotOffset(Context::PREVIOUS_INDEX))); |
| 3336 } | 3338 } |
| 3337 | 3339 |
| 3338 | 3340 |
| 3339 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { | 3341 void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { |
| 3340 ASSERT(ToRegister(instr->context()).is(rsi)); | 3342 ASSERT(ToRegister(instr->context()).is(rsi)); |
| 3341 __ push(rsi); // The context is the first argument. | 3343 __ push(rsi); // The context is the first argument. |
| 3342 __ Push(instr->hydrogen()->pairs()); | 3344 __ Push(instr->hydrogen()->pairs()); |
| 3343 __ Push(Smi::FromInt(instr->hydrogen()->flags())); | 3345 __ Push(Smi::FromInt(instr->hydrogen()->flags())); |
| 3344 CallRuntime(Runtime::kDeclareGlobals, 3, instr); | 3346 CallRuntime(Runtime::kDeclareGlobals, 3, instr); |
| 3345 } | 3347 } |
| 3346 | 3348 |
| 3347 | 3349 |
| 3348 void LCodeGen::DoGlobalObject(LGlobalObject* instr) { | 3350 void LCodeGen::DoGlobalObject(LGlobalObject* instr) { |
| 3349 Register context = ToRegister(instr->context()); | 3351 Register context = ToRegister(instr->context()); |
| 3350 Register result = ToRegister(instr->result()); | 3352 Register result = ToRegister(instr->result()); |
| 3351 __ movq(result, | 3353 __ movp(result, |
| 3352 Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | 3354 Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); |
| 3353 } | 3355 } |
| 3354 | 3356 |
| 3355 | 3357 |
| 3356 void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { | 3358 void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) { |
| 3357 Register global = ToRegister(instr->global()); | 3359 Register global = ToRegister(instr->global()); |
| 3358 Register result = ToRegister(instr->result()); | 3360 Register result = ToRegister(instr->result()); |
| 3359 __ movq(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset)); | 3361 __ movp(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset)); |
| 3360 } | 3362 } |
| 3361 | 3363 |
| 3362 | 3364 |
| 3363 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, | 3365 void LCodeGen::CallKnownFunction(Handle<JSFunction> function, |
| 3364 int formal_parameter_count, | 3366 int formal_parameter_count, |
| 3365 int arity, | 3367 int arity, |
| 3366 LInstruction* instr, | 3368 LInstruction* instr, |
| 3367 RDIState rdi_state) { | 3369 RDIState rdi_state) { |
| 3368 bool dont_adapt_arguments = | 3370 bool dont_adapt_arguments = |
| 3369 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; | 3371 formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel; |
| 3370 bool can_invoke_directly = | 3372 bool can_invoke_directly = |
| 3371 dont_adapt_arguments || formal_parameter_count == arity; | 3373 dont_adapt_arguments || formal_parameter_count == arity; |
| 3372 | 3374 |
| 3373 LPointerMap* pointers = instr->pointer_map(); | 3375 LPointerMap* pointers = instr->pointer_map(); |
| 3374 | 3376 |
| 3375 if (can_invoke_directly) { | 3377 if (can_invoke_directly) { |
| 3376 if (rdi_state == RDI_UNINITIALIZED) { | 3378 if (rdi_state == RDI_UNINITIALIZED) { |
| 3377 __ Move(rdi, function); | 3379 __ Move(rdi, function); |
| 3378 } | 3380 } |
| 3379 | 3381 |
| 3380 // Change context. | 3382 // Change context. |
| 3381 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); | 3383 __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
| 3382 | 3384 |
| 3383 // Set rax to arguments count if adaption is not needed. Assumes that rax | 3385 // Set rax to arguments count if adaption is not needed. Assumes that rax |
| 3384 // is available to write to at this point. | 3386 // is available to write to at this point. |
| 3385 if (dont_adapt_arguments) { | 3387 if (dont_adapt_arguments) { |
| 3386 __ Set(rax, arity); | 3388 __ Set(rax, arity); |
| 3387 } | 3389 } |
| 3388 | 3390 |
| 3389 // Invoke function. | 3391 // Invoke function. |
| 3390 if (function.is_identical_to(info()->closure())) { | 3392 if (function.is_identical_to(info()->closure())) { |
| 3391 __ CallSelf(); | 3393 __ CallSelf(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3430 | 3432 |
| 3431 void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) { | 3433 void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) { |
| 3432 ASSERT(ToRegister(instr->function()).is(rdi)); | 3434 ASSERT(ToRegister(instr->function()).is(rdi)); |
| 3433 ASSERT(ToRegister(instr->result()).is(rax)); | 3435 ASSERT(ToRegister(instr->result()).is(rax)); |
| 3434 | 3436 |
| 3435 if (instr->hydrogen()->pass_argument_count()) { | 3437 if (instr->hydrogen()->pass_argument_count()) { |
| 3436 __ Set(rax, instr->arity()); | 3438 __ Set(rax, instr->arity()); |
| 3437 } | 3439 } |
| 3438 | 3440 |
| 3439 // Change context. | 3441 // Change context. |
| 3440 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); | 3442 __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
| 3441 | 3443 |
| 3442 LPointerMap* pointers = instr->pointer_map(); | 3444 LPointerMap* pointers = instr->pointer_map(); |
| 3443 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); | 3445 SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt); |
| 3444 | 3446 |
| 3445 bool is_self_call = false; | 3447 bool is_self_call = false; |
| 3446 if (instr->hydrogen()->function()->IsConstant()) { | 3448 if (instr->hydrogen()->function()->IsConstant()) { |
| 3447 Handle<JSFunction> jsfun = Handle<JSFunction>::null(); | 3449 Handle<JSFunction> jsfun = Handle<JSFunction>::null(); |
| 3448 HConstant* fun_const = HConstant::cast(instr->hydrogen()->function()); | 3450 HConstant* fun_const = HConstant::cast(instr->hydrogen()->function()); |
| 3449 jsfun = Handle<JSFunction>::cast(fun_const->handle(isolate())); | 3451 jsfun = Handle<JSFunction>::cast(fun_const->handle(isolate())); |
| 3450 is_self_call = jsfun.is_identical_to(info()->closure()); | 3452 is_self_call = jsfun.is_identical_to(info()->closure()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3483 __ j(zero, &done); | 3485 __ j(zero, &done); |
| 3484 | 3486 |
| 3485 __ AllocateHeapNumber(tmp, tmp2, &slow); | 3487 __ AllocateHeapNumber(tmp, tmp2, &slow); |
| 3486 __ jmp(&allocated, Label::kNear); | 3488 __ jmp(&allocated, Label::kNear); |
| 3487 | 3489 |
| 3488 // Slow case: Call the runtime system to do the number allocation. | 3490 // Slow case: Call the runtime system to do the number allocation. |
| 3489 __ bind(&slow); | 3491 __ bind(&slow); |
| 3490 CallRuntimeFromDeferred( | 3492 CallRuntimeFromDeferred( |
| 3491 Runtime::kAllocateHeapNumber, 0, instr, instr->context()); | 3493 Runtime::kAllocateHeapNumber, 0, instr, instr->context()); |
| 3492 // Set the pointer to the new heap number in tmp. | 3494 // Set the pointer to the new heap number in tmp. |
| 3493 if (!tmp.is(rax)) __ movq(tmp, rax); | 3495 if (!tmp.is(rax)) __ movp(tmp, rax); |
| 3494 // Restore input_reg after call to runtime. | 3496 // Restore input_reg after call to runtime. |
| 3495 __ LoadFromSafepointRegisterSlot(input_reg, input_reg); | 3497 __ LoadFromSafepointRegisterSlot(input_reg, input_reg); |
| 3496 | 3498 |
| 3497 __ bind(&allocated); | 3499 __ bind(&allocated); |
| 3498 __ MoveDouble(tmp2, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 3500 __ MoveDouble(tmp2, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| 3499 __ shl(tmp2, Immediate(1)); | 3501 __ shl(tmp2, Immediate(1)); |
| 3500 __ shr(tmp2, Immediate(1)); | 3502 __ shr(tmp2, Immediate(1)); |
| 3501 __ MoveDouble(FieldOperand(tmp, HeapNumber::kValueOffset), tmp2); | 3503 __ MoveDouble(FieldOperand(tmp, HeapNumber::kValueOffset), tmp2); |
| 3502 __ StoreToSafepointRegisterSlot(input_reg, tmp); | 3504 __ StoreToSafepointRegisterSlot(input_reg, tmp); |
| 3503 | 3505 |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3855 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 3857 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 3856 } | 3858 } |
| 3857 | 3859 |
| 3858 | 3860 |
| 3859 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { | 3861 void LCodeGen::DoCallNewArray(LCallNewArray* instr) { |
| 3860 ASSERT(ToRegister(instr->context()).is(rsi)); | 3862 ASSERT(ToRegister(instr->context()).is(rsi)); |
| 3861 ASSERT(ToRegister(instr->constructor()).is(rdi)); | 3863 ASSERT(ToRegister(instr->constructor()).is(rdi)); |
| 3862 ASSERT(ToRegister(instr->result()).is(rax)); | 3864 ASSERT(ToRegister(instr->result()).is(rax)); |
| 3863 | 3865 |
| 3864 __ Set(rax, instr->arity()); | 3866 __ Set(rax, instr->arity()); |
| 3865 __ Move(rbx, instr->hydrogen()->property_cell()); | 3867 __ Move(rbx, factory()->undefined_value()); |
| 3866 ElementsKind kind = instr->hydrogen()->elements_kind(); | 3868 ElementsKind kind = instr->hydrogen()->elements_kind(); |
| 3867 AllocationSiteOverrideMode override_mode = | 3869 AllocationSiteOverrideMode override_mode = |
| 3868 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE) | 3870 (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE) |
| 3869 ? DISABLE_ALLOCATION_SITES | 3871 ? DISABLE_ALLOCATION_SITES |
| 3870 : DONT_OVERRIDE; | 3872 : DONT_OVERRIDE; |
| 3871 | 3873 |
| 3872 if (instr->arity() == 0) { | 3874 if (instr->arity() == 0) { |
| 3873 ArrayNoArgumentConstructorStub stub(kind, override_mode); | 3875 ArrayNoArgumentConstructorStub stub(kind, override_mode); |
| 3874 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 3876 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 3875 } else if (instr->arity() == 1) { | 3877 } else if (instr->arity() == 1) { |
| 3876 Label done; | 3878 Label done; |
| 3877 if (IsFastPackedElementsKind(kind)) { | 3879 if (IsFastPackedElementsKind(kind)) { |
| 3878 Label packed_case; | 3880 Label packed_case; |
| 3879 // We might need a change here | 3881 // We might need a change here |
| 3880 // look at the first argument | 3882 // look at the first argument |
| 3881 __ movq(rcx, Operand(rsp, 0)); | 3883 __ movp(rcx, Operand(rsp, 0)); |
| 3882 __ testq(rcx, rcx); | 3884 __ testq(rcx, rcx); |
| 3883 __ j(zero, &packed_case, Label::kNear); | 3885 __ j(zero, &packed_case, Label::kNear); |
| 3884 | 3886 |
| 3885 ElementsKind holey_kind = GetHoleyElementsKind(kind); | 3887 ElementsKind holey_kind = GetHoleyElementsKind(kind); |
| 3886 ArraySingleArgumentConstructorStub stub(holey_kind, override_mode); | 3888 ArraySingleArgumentConstructorStub stub(holey_kind, override_mode); |
| 3887 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); | 3889 CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr); |
| 3888 __ jmp(&done, Label::kNear); | 3890 __ jmp(&done, Label::kNear); |
| 3889 __ bind(&packed_case); | 3891 __ bind(&packed_case); |
| 3890 } | 3892 } |
| 3891 | 3893 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3902 void LCodeGen::DoCallRuntime(LCallRuntime* instr) { | 3904 void LCodeGen::DoCallRuntime(LCallRuntime* instr) { |
| 3903 ASSERT(ToRegister(instr->context()).is(rsi)); | 3905 ASSERT(ToRegister(instr->context()).is(rsi)); |
| 3904 CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles()); | 3906 CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles()); |
| 3905 } | 3907 } |
| 3906 | 3908 |
| 3907 | 3909 |
| 3908 void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) { | 3910 void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) { |
| 3909 Register function = ToRegister(instr->function()); | 3911 Register function = ToRegister(instr->function()); |
| 3910 Register code_object = ToRegister(instr->code_object()); | 3912 Register code_object = ToRegister(instr->code_object()); |
| 3911 __ lea(code_object, FieldOperand(code_object, Code::kHeaderSize)); | 3913 __ lea(code_object, FieldOperand(code_object, Code::kHeaderSize)); |
| 3912 __ movq(FieldOperand(function, JSFunction::kCodeEntryOffset), code_object); | 3914 __ movp(FieldOperand(function, JSFunction::kCodeEntryOffset), code_object); |
| 3913 } | 3915 } |
| 3914 | 3916 |
| 3915 | 3917 |
| 3916 void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) { | 3918 void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) { |
| 3917 Register result = ToRegister(instr->result()); | 3919 Register result = ToRegister(instr->result()); |
| 3918 Register base = ToRegister(instr->base_object()); | 3920 Register base = ToRegister(instr->base_object()); |
| 3919 if (instr->offset()->IsConstantOperand()) { | 3921 if (instr->offset()->IsConstantOperand()) { |
| 3920 LConstantOperand* offset = LConstantOperand::cast(instr->offset()); | 3922 LConstantOperand* offset = LConstantOperand::cast(instr->offset()); |
| 3921 __ lea(result, Operand(base, ToInteger32(offset))); | 3923 __ lea(result, Operand(base, ToInteger32(offset))); |
| 3922 } else { | 3924 } else { |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3980 __ movsd(FieldOperand(object, offset), value); | 3982 __ movsd(FieldOperand(object, offset), value); |
| 3981 return; | 3983 return; |
| 3982 } | 3984 } |
| 3983 | 3985 |
| 3984 if (!transition.is_null()) { | 3986 if (!transition.is_null()) { |
| 3985 if (!hinstr->NeedsWriteBarrierForMap()) { | 3987 if (!hinstr->NeedsWriteBarrierForMap()) { |
| 3986 __ Move(FieldOperand(object, HeapObject::kMapOffset), transition); | 3988 __ Move(FieldOperand(object, HeapObject::kMapOffset), transition); |
| 3987 } else { | 3989 } else { |
| 3988 Register temp = ToRegister(instr->temp()); | 3990 Register temp = ToRegister(instr->temp()); |
| 3989 __ Move(kScratchRegister, transition); | 3991 __ Move(kScratchRegister, transition); |
| 3990 __ movq(FieldOperand(object, HeapObject::kMapOffset), kScratchRegister); | 3992 __ movp(FieldOperand(object, HeapObject::kMapOffset), kScratchRegister); |
| 3991 // Update the write barrier for the map field. | 3993 // Update the write barrier for the map field. |
| 3992 __ RecordWriteField(object, | 3994 __ RecordWriteField(object, |
| 3993 HeapObject::kMapOffset, | 3995 HeapObject::kMapOffset, |
| 3994 kScratchRegister, | 3996 kScratchRegister, |
| 3995 temp, | 3997 temp, |
| 3996 kSaveFPRegs, | 3998 kSaveFPRegs, |
| 3997 OMIT_REMEMBERED_SET, | 3999 OMIT_REMEMBERED_SET, |
| 3998 OMIT_SMI_CHECK); | 4000 OMIT_SMI_CHECK); |
| 3999 } | 4001 } |
| 4000 } | 4002 } |
| 4001 | 4003 |
| 4002 // Do the store. | 4004 // Do the store. |
| 4003 SmiCheck check_needed = hinstr->value()->IsHeapObject() | 4005 SmiCheck check_needed = hinstr->value()->IsHeapObject() |
| 4004 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; | 4006 ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
| 4005 | 4007 |
| 4006 Register write_register = object; | 4008 Register write_register = object; |
| 4007 if (!access.IsInobject()) { | 4009 if (!access.IsInobject()) { |
| 4008 write_register = ToRegister(instr->temp()); | 4010 write_register = ToRegister(instr->temp()); |
| 4009 __ movq(write_register, FieldOperand(object, JSObject::kPropertiesOffset)); | 4011 __ movp(write_register, FieldOperand(object, JSObject::kPropertiesOffset)); |
| 4010 } | 4012 } |
| 4011 | 4013 |
| 4012 if (representation.IsSmi() && | 4014 if (representation.IsSmi() && |
| 4013 hinstr->value()->representation().IsInteger32()) { | 4015 hinstr->value()->representation().IsInteger32()) { |
| 4014 ASSERT(hinstr->store_mode() == STORE_TO_INITIALIZED_ENTRY); | 4016 ASSERT(hinstr->store_mode() == STORE_TO_INITIALIZED_ENTRY); |
| 4015 // Store int value directly to upper half of the smi. | 4017 // Store int value directly to upper half of the smi. |
| 4016 STATIC_ASSERT(kSmiTag == 0); | 4018 STATIC_ASSERT(kSmiTag == 0); |
| 4017 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32); | 4019 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 32); |
| 4018 offset += kPointerSize / 2; | 4020 offset += kPointerSize / 2; |
| 4019 representation = Representation::Integer32(); | 4021 representation = Representation::Integer32(); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4058 } | 4060 } |
| 4059 | 4061 |
| 4060 | 4062 |
| 4061 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { | 4063 void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) { |
| 4062 ASSERT(ToRegister(instr->context()).is(rsi)); | 4064 ASSERT(ToRegister(instr->context()).is(rsi)); |
| 4063 ASSERT(ToRegister(instr->object()).is(rdx)); | 4065 ASSERT(ToRegister(instr->object()).is(rdx)); |
| 4064 ASSERT(ToRegister(instr->value()).is(rax)); | 4066 ASSERT(ToRegister(instr->value()).is(rax)); |
| 4065 | 4067 |
| 4066 __ Move(rcx, instr->hydrogen()->name()); | 4068 __ Move(rcx, instr->hydrogen()->name()); |
| 4067 Handle<Code> ic = StoreIC::initialize_stub(isolate(), | 4069 Handle<Code> ic = StoreIC::initialize_stub(isolate(), |
| 4068 instr->strict_mode_flag(), | 4070 instr->strict_mode_flag()); |
| 4069 NOT_CONTEXTUAL); | |
| 4070 CallCode(ic, RelocInfo::CODE_TARGET, instr); | 4071 CallCode(ic, RelocInfo::CODE_TARGET, instr); |
| 4071 } | 4072 } |
| 4072 | 4073 |
| 4073 | 4074 |
| 4074 void LCodeGen::ApplyCheckIf(Condition cc, LBoundsCheck* check) { | 4075 void LCodeGen::ApplyCheckIf(Condition cc, LBoundsCheck* check) { |
| 4075 if (FLAG_debug_code && check->hydrogen()->skip_check()) { | 4076 if (FLAG_debug_code && check->hydrogen()->skip_check()) { |
| 4076 Label done; | 4077 Label done; |
| 4077 __ j(NegateCondition(cc), &done, Label::kNear); | 4078 __ j(NegateCondition(cc), &done, Label::kNear); |
| 4078 __ int3(); | 4079 __ int3(); |
| 4079 __ bind(&done); | 4080 __ bind(&done); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4135 // the input representation for the key to be an integer, the input | 4136 // the input representation for the key to be an integer, the input |
| 4136 // gets replaced during bound check elimination with the index | 4137 // gets replaced during bound check elimination with the index |
| 4137 // argument to the bounds check, which can be tagged, so that case | 4138 // argument to the bounds check, which can be tagged, so that case |
| 4138 // must be handled here, too. | 4139 // must be handled here, too. |
| 4139 if (instr->hydrogen()->IsDehoisted()) { | 4140 if (instr->hydrogen()->IsDehoisted()) { |
| 4140 // Sign extend key because it could be a 32 bit negative value | 4141 // Sign extend key because it could be a 32 bit negative value |
| 4141 // and the dehoisted address computation happens in 64 bits | 4142 // and the dehoisted address computation happens in 64 bits |
| 4142 __ movsxlq(key_reg, key_reg); | 4143 __ movsxlq(key_reg, key_reg); |
| 4143 } | 4144 } |
| 4144 } | 4145 } |
| 4146 int base_offset = instr->is_fixed_typed_array() |
| 4147 ? FixedTypedArrayBase::kDataOffset - kHeapObjectTag |
| 4148 : 0; |
| 4145 Operand operand(BuildFastArrayOperand( | 4149 Operand operand(BuildFastArrayOperand( |
| 4146 instr->elements(), | 4150 instr->elements(), |
| 4147 key, | 4151 key, |
| 4148 elements_kind, | 4152 elements_kind, |
| 4149 0, | 4153 base_offset, |
| 4150 instr->additional_index())); | 4154 instr->additional_index())); |
| 4151 | 4155 |
| 4152 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS) { | 4156 if (elements_kind == EXTERNAL_FLOAT_ELEMENTS || |
| 4157 elements_kind == FLOAT32_ELEMENTS) { |
| 4153 XMMRegister value(ToDoubleRegister(instr->value())); | 4158 XMMRegister value(ToDoubleRegister(instr->value())); |
| 4154 __ cvtsd2ss(value, value); | 4159 __ cvtsd2ss(value, value); |
| 4155 __ movss(operand, value); | 4160 __ movss(operand, value); |
| 4156 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS) { | 4161 } else if (elements_kind == EXTERNAL_DOUBLE_ELEMENTS || |
| 4162 elements_kind == FLOAT64_ELEMENTS) { |
| 4157 __ movsd(operand, ToDoubleRegister(instr->value())); | 4163 __ movsd(operand, ToDoubleRegister(instr->value())); |
| 4158 } else { | 4164 } else { |
| 4159 Register value(ToRegister(instr->value())); | 4165 Register value(ToRegister(instr->value())); |
| 4160 switch (elements_kind) { | 4166 switch (elements_kind) { |
| 4161 case EXTERNAL_PIXEL_ELEMENTS: | 4167 case EXTERNAL_PIXEL_ELEMENTS: |
| 4162 case EXTERNAL_BYTE_ELEMENTS: | 4168 case EXTERNAL_BYTE_ELEMENTS: |
| 4163 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: | 4169 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: |
| 4170 case INT8_ELEMENTS: |
| 4171 case UINT8_ELEMENTS: |
| 4172 case UINT8_CLAMPED_ELEMENTS: |
| 4164 __ movb(operand, value); | 4173 __ movb(operand, value); |
| 4165 break; | 4174 break; |
| 4166 case EXTERNAL_SHORT_ELEMENTS: | 4175 case EXTERNAL_SHORT_ELEMENTS: |
| 4167 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: | 4176 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: |
| 4177 case INT16_ELEMENTS: |
| 4178 case UINT16_ELEMENTS: |
| 4168 __ movw(operand, value); | 4179 __ movw(operand, value); |
| 4169 break; | 4180 break; |
| 4170 case EXTERNAL_INT_ELEMENTS: | 4181 case EXTERNAL_INT_ELEMENTS: |
| 4171 case EXTERNAL_UNSIGNED_INT_ELEMENTS: | 4182 case EXTERNAL_UNSIGNED_INT_ELEMENTS: |
| 4183 case INT32_ELEMENTS: |
| 4184 case UINT32_ELEMENTS: |
| 4172 __ movl(operand, value); | 4185 __ movl(operand, value); |
| 4173 break; | 4186 break; |
| 4174 case EXTERNAL_FLOAT_ELEMENTS: | 4187 case EXTERNAL_FLOAT_ELEMENTS: |
| 4175 case EXTERNAL_DOUBLE_ELEMENTS: | 4188 case EXTERNAL_DOUBLE_ELEMENTS: |
| 4189 case FLOAT32_ELEMENTS: |
| 4190 case FLOAT64_ELEMENTS: |
| 4176 case FAST_ELEMENTS: | 4191 case FAST_ELEMENTS: |
| 4177 case FAST_SMI_ELEMENTS: | 4192 case FAST_SMI_ELEMENTS: |
| 4178 case FAST_DOUBLE_ELEMENTS: | 4193 case FAST_DOUBLE_ELEMENTS: |
| 4179 case FAST_HOLEY_ELEMENTS: | 4194 case FAST_HOLEY_ELEMENTS: |
| 4180 case FAST_HOLEY_SMI_ELEMENTS: | 4195 case FAST_HOLEY_SMI_ELEMENTS: |
| 4181 case FAST_HOLEY_DOUBLE_ELEMENTS: | 4196 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 4182 case DICTIONARY_ELEMENTS: | 4197 case DICTIONARY_ELEMENTS: |
| 4183 case NON_STRICT_ARGUMENTS_ELEMENTS: | 4198 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 4184 UNREACHABLE(); | 4199 UNREACHABLE(); |
| 4185 break; | 4200 break; |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4297 key_reg, | 4312 key_reg, |
| 4298 value, | 4313 value, |
| 4299 kSaveFPRegs, | 4314 kSaveFPRegs, |
| 4300 EMIT_REMEMBERED_SET, | 4315 EMIT_REMEMBERED_SET, |
| 4301 check_needed); | 4316 check_needed); |
| 4302 } | 4317 } |
| 4303 } | 4318 } |
| 4304 | 4319 |
| 4305 | 4320 |
| 4306 void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { | 4321 void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { |
| 4307 if (instr->is_external()) { | 4322 if (instr->is_typed_elements()) { |
| 4308 DoStoreKeyedExternalArray(instr); | 4323 DoStoreKeyedExternalArray(instr); |
| 4309 } else if (instr->hydrogen()->value()->representation().IsDouble()) { | 4324 } else if (instr->hydrogen()->value()->representation().IsDouble()) { |
| 4310 DoStoreKeyedFixedDoubleArray(instr); | 4325 DoStoreKeyedFixedDoubleArray(instr); |
| 4311 } else { | 4326 } else { |
| 4312 DoStoreKeyedFixedArray(instr); | 4327 DoStoreKeyedFixedArray(instr); |
| 4313 } | 4328 } |
| 4314 } | 4329 } |
| 4315 | 4330 |
| 4316 | 4331 |
| 4317 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { | 4332 void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 4334 Handle<Map> to_map = instr->transitioned_map(); | 4349 Handle<Map> to_map = instr->transitioned_map(); |
| 4335 ElementsKind from_kind = instr->from_kind(); | 4350 ElementsKind from_kind = instr->from_kind(); |
| 4336 ElementsKind to_kind = instr->to_kind(); | 4351 ElementsKind to_kind = instr->to_kind(); |
| 4337 | 4352 |
| 4338 Label not_applicable; | 4353 Label not_applicable; |
| 4339 __ Cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map); | 4354 __ Cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map); |
| 4340 __ j(not_equal, ¬_applicable); | 4355 __ j(not_equal, ¬_applicable); |
| 4341 if (IsSimpleMapChangeTransition(from_kind, to_kind)) { | 4356 if (IsSimpleMapChangeTransition(from_kind, to_kind)) { |
| 4342 Register new_map_reg = ToRegister(instr->new_map_temp()); | 4357 Register new_map_reg = ToRegister(instr->new_map_temp()); |
| 4343 __ Move(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT); | 4358 __ Move(new_map_reg, to_map, RelocInfo::EMBEDDED_OBJECT); |
| 4344 __ movq(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg); | 4359 __ movp(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg); |
| 4345 // Write barrier. | 4360 // Write barrier. |
| 4346 ASSERT_NE(instr->temp(), NULL); | 4361 ASSERT_NE(instr->temp(), NULL); |
| 4347 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, | 4362 __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, |
| 4348 ToRegister(instr->temp()), kDontSaveFPRegs); | 4363 ToRegister(instr->temp()), kDontSaveFPRegs); |
| 4349 } else { | 4364 } else { |
| 4350 ASSERT(ToRegister(instr->context()).is(rsi)); | 4365 ASSERT(ToRegister(instr->context()).is(rsi)); |
| 4351 PushSafepointRegistersScope scope(this); | 4366 PushSafepointRegistersScope scope(this); |
| 4352 if (!object_reg.is(rax)) { | 4367 if (!object_reg.is(rax)) { |
| 4353 __ movq(rax, object_reg); | 4368 __ movp(rax, object_reg); |
| 4354 } | 4369 } |
| 4355 __ Move(rbx, to_map); | 4370 __ Move(rbx, to_map); |
| 4356 TransitionElementsKindStub stub(from_kind, to_kind); | 4371 TransitionElementsKindStub stub(from_kind, to_kind); |
| 4357 __ CallStub(&stub); | 4372 __ CallStub(&stub); |
| 4358 RecordSafepointWithRegisters( | 4373 RecordSafepointWithRegisters( |
| 4359 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); | 4374 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); |
| 4360 } | 4375 } |
| 4361 __ bind(¬_applicable); | 4376 __ bind(¬_applicable); |
| 4362 } | 4377 } |
| 4363 | 4378 |
| 4364 | 4379 |
| 4365 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { | 4380 void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { |
| 4366 Register object = ToRegister(instr->object()); | 4381 Register object = ToRegister(instr->object()); |
| 4367 Register temp = ToRegister(instr->temp()); | 4382 Register temp = ToRegister(instr->temp()); |
| 4368 Label no_memento_found; | 4383 Label no_memento_found; |
| 4369 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found); | 4384 __ TestJSArrayForAllocationMemento(object, temp, &no_memento_found); |
| 4370 DeoptimizeIf(equal, instr->environment()); | 4385 DeoptimizeIf(equal, instr->environment()); |
| 4371 __ bind(&no_memento_found); | 4386 __ bind(&no_memento_found); |
| 4372 } | 4387 } |
| 4373 | 4388 |
| 4374 | 4389 |
| 4375 void LCodeGen::DoStringAdd(LStringAdd* instr) { | 4390 void LCodeGen::DoStringAdd(LStringAdd* instr) { |
| 4376 ASSERT(ToRegister(instr->context()).is(rsi)); | 4391 ASSERT(ToRegister(instr->context()).is(rsi)); |
| 4377 if (FLAG_new_string_add) { | 4392 ASSERT(ToRegister(instr->left()).is(rdx)); |
| 4378 ASSERT(ToRegister(instr->left()).is(rdx)); | 4393 ASSERT(ToRegister(instr->right()).is(rax)); |
| 4379 ASSERT(ToRegister(instr->right()).is(rax)); | 4394 StringAddStub stub(instr->hydrogen()->flags(), |
| 4380 NewStringAddStub stub(instr->hydrogen()->flags(), | 4395 isolate()->heap()->GetPretenureMode()); |
| 4381 isolate()->heap()->GetPretenureMode()); | 4396 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); |
| 4382 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); | |
| 4383 } else { | |
| 4384 EmitPushTaggedOperand(instr->left()); | |
| 4385 EmitPushTaggedOperand(instr->right()); | |
| 4386 StringAddStub stub(instr->hydrogen()->flags()); | |
| 4387 CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr); | |
| 4388 } | |
| 4389 } | 4397 } |
| 4390 | 4398 |
| 4391 | 4399 |
| 4392 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { | 4400 void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
| 4393 class DeferredStringCharCodeAt V8_FINAL : public LDeferredCode { | 4401 class DeferredStringCharCodeAt V8_FINAL : public LDeferredCode { |
| 4394 public: | 4402 public: |
| 4395 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) | 4403 DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) |
| 4396 : LDeferredCode(codegen), instr_(instr) { } | 4404 : LDeferredCode(codegen), instr_(instr) { } |
| 4397 virtual void Generate() V8_OVERRIDE { | 4405 virtual void Generate() V8_OVERRIDE { |
| 4398 codegen()->DoDeferredStringCharCodeAt(instr_); | 4406 codegen()->DoDeferredStringCharCodeAt(instr_); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4462 | 4470 |
| 4463 ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); | 4471 ASSERT(instr->hydrogen()->value()->representation().IsInteger32()); |
| 4464 Register char_code = ToRegister(instr->char_code()); | 4472 Register char_code = ToRegister(instr->char_code()); |
| 4465 Register result = ToRegister(instr->result()); | 4473 Register result = ToRegister(instr->result()); |
| 4466 ASSERT(!char_code.is(result)); | 4474 ASSERT(!char_code.is(result)); |
| 4467 | 4475 |
| 4468 __ cmpl(char_code, Immediate(String::kMaxOneByteCharCode)); | 4476 __ cmpl(char_code, Immediate(String::kMaxOneByteCharCode)); |
| 4469 __ j(above, deferred->entry()); | 4477 __ j(above, deferred->entry()); |
| 4470 __ movsxlq(char_code, char_code); | 4478 __ movsxlq(char_code, char_code); |
| 4471 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex); | 4479 __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex); |
| 4472 __ movq(result, FieldOperand(result, | 4480 __ movp(result, FieldOperand(result, |
| 4473 char_code, times_pointer_size, | 4481 char_code, times_pointer_size, |
| 4474 FixedArray::kHeaderSize)); | 4482 FixedArray::kHeaderSize)); |
| 4475 __ CompareRoot(result, Heap::kUndefinedValueRootIndex); | 4483 __ CompareRoot(result, Heap::kUndefinedValueRootIndex); |
| 4476 __ j(equal, deferred->entry()); | 4484 __ j(equal, deferred->entry()); |
| 4477 __ bind(deferred->exit()); | 4485 __ bind(deferred->exit()); |
| 4478 } | 4486 } |
| 4479 | 4487 |
| 4480 | 4488 |
| 4481 void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) { | 4489 void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) { |
| 4482 Register char_code = ToRegister(instr->char_code()); | 4490 Register char_code = ToRegister(instr->char_code()); |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4608 // Put a valid pointer value in the stack slot where the result | 4616 // Put a valid pointer value in the stack slot where the result |
| 4609 // register is stored, as this register is in the pointer map, but contains an | 4617 // register is stored, as this register is in the pointer map, but contains an |
| 4610 // integer value. | 4618 // integer value. |
| 4611 __ StoreToSafepointRegisterSlot(reg, Immediate(0)); | 4619 __ StoreToSafepointRegisterSlot(reg, Immediate(0)); |
| 4612 | 4620 |
| 4613 // NumberTagU uses the context from the frame, rather than | 4621 // NumberTagU uses the context from the frame, rather than |
| 4614 // the environment's HContext or HInlinedContext value. | 4622 // the environment's HContext or HInlinedContext value. |
| 4615 // They only call Runtime::kAllocateHeapNumber. | 4623 // They only call Runtime::kAllocateHeapNumber. |
| 4616 // The corresponding HChange instructions are added in a phase that does | 4624 // The corresponding HChange instructions are added in a phase that does |
| 4617 // not have easy access to the local context. | 4625 // not have easy access to the local context. |
| 4618 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 4626 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 4619 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); | 4627 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 4620 RecordSafepointWithRegisters( | 4628 RecordSafepointWithRegisters( |
| 4621 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); | 4629 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); |
| 4622 | 4630 |
| 4623 if (!reg.is(rax)) __ movq(reg, rax); | 4631 if (!reg.is(rax)) __ movp(reg, rax); |
| 4624 | 4632 |
| 4625 // Done. Put the value in temp_xmm into the value of the allocated heap | 4633 // Done. Put the value in temp_xmm into the value of the allocated heap |
| 4626 // number. | 4634 // number. |
| 4627 __ bind(&done); | 4635 __ bind(&done); |
| 4628 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), temp_xmm); | 4636 __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), temp_xmm); |
| 4629 __ StoreToSafepointRegisterSlot(reg, reg); | 4637 __ StoreToSafepointRegisterSlot(reg, reg); |
| 4630 } | 4638 } |
| 4631 | 4639 |
| 4632 | 4640 |
| 4633 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { | 4641 void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4665 Register reg = ToRegister(instr->result()); | 4673 Register reg = ToRegister(instr->result()); |
| 4666 __ Move(reg, Smi::FromInt(0)); | 4674 __ Move(reg, Smi::FromInt(0)); |
| 4667 | 4675 |
| 4668 { | 4676 { |
| 4669 PushSafepointRegistersScope scope(this); | 4677 PushSafepointRegistersScope scope(this); |
| 4670 // NumberTagD uses the context from the frame, rather than | 4678 // NumberTagD uses the context from the frame, rather than |
| 4671 // the environment's HContext or HInlinedContext value. | 4679 // the environment's HContext or HInlinedContext value. |
| 4672 // They only call Runtime::kAllocateHeapNumber. | 4680 // They only call Runtime::kAllocateHeapNumber. |
| 4673 // The corresponding HChange instructions are added in a phase that does | 4681 // The corresponding HChange instructions are added in a phase that does |
| 4674 // not have easy access to the local context. | 4682 // not have easy access to the local context. |
| 4675 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 4683 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 4676 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); | 4684 __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
| 4677 RecordSafepointWithRegisters( | 4685 RecordSafepointWithRegisters( |
| 4678 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); | 4686 instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); |
| 4679 __ movq(kScratchRegister, rax); | 4687 __ movp(kScratchRegister, rax); |
| 4680 } | 4688 } |
| 4681 __ movq(reg, kScratchRegister); | 4689 __ movp(reg, kScratchRegister); |
| 4682 } | 4690 } |
| 4683 | 4691 |
| 4684 | 4692 |
| 4685 void LCodeGen::DoSmiTag(LSmiTag* instr) { | 4693 void LCodeGen::DoSmiTag(LSmiTag* instr) { |
| 4686 ASSERT(instr->value()->Equals(instr->result())); | 4694 ASSERT(instr->value()->Equals(instr->result())); |
| 4687 Register input = ToRegister(instr->value()); | 4695 Register input = ToRegister(instr->value()); |
| 4688 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); | 4696 ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow)); |
| 4689 __ Integer32ToSmi(input, input); | 4697 __ Integer32ToSmi(input, input); |
| 4690 } | 4698 } |
| 4691 | 4699 |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4920 LOperand* input = instr->value(); | 4928 LOperand* input = instr->value(); |
| 4921 Condition cc = masm()->CheckSmi(ToRegister(input)); | 4929 Condition cc = masm()->CheckSmi(ToRegister(input)); |
| 4922 DeoptimizeIf(cc, instr->environment()); | 4930 DeoptimizeIf(cc, instr->environment()); |
| 4923 } | 4931 } |
| 4924 } | 4932 } |
| 4925 | 4933 |
| 4926 | 4934 |
| 4927 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { | 4935 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) { |
| 4928 Register input = ToRegister(instr->value()); | 4936 Register input = ToRegister(instr->value()); |
| 4929 | 4937 |
| 4930 __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset)); | 4938 __ movp(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset)); |
| 4931 | 4939 |
| 4932 if (instr->hydrogen()->is_interval_check()) { | 4940 if (instr->hydrogen()->is_interval_check()) { |
| 4933 InstanceType first; | 4941 InstanceType first; |
| 4934 InstanceType last; | 4942 InstanceType last; |
| 4935 instr->hydrogen()->GetCheckInterval(&first, &last); | 4943 instr->hydrogen()->GetCheckInterval(&first, &last); |
| 4936 | 4944 |
| 4937 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset), | 4945 __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset), |
| 4938 Immediate(static_cast<int8_t>(first))); | 4946 Immediate(static_cast<int8_t>(first))); |
| 4939 | 4947 |
| 4940 // If there is only one type in the interval check for equality. | 4948 // If there is only one type in the interval check for equality. |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5068 | 5076 |
| 5069 // Check for heap number | 5077 // Check for heap number |
| 5070 __ Cmp(FieldOperand(input_reg, HeapObject::kMapOffset), | 5078 __ Cmp(FieldOperand(input_reg, HeapObject::kMapOffset), |
| 5071 factory()->heap_number_map()); | 5079 factory()->heap_number_map()); |
| 5072 __ j(equal, &heap_number, Label::kNear); | 5080 __ j(equal, &heap_number, Label::kNear); |
| 5073 | 5081 |
| 5074 // Check for undefined. Undefined is converted to zero for clamping | 5082 // Check for undefined. Undefined is converted to zero for clamping |
| 5075 // conversions. | 5083 // conversions. |
| 5076 __ Cmp(input_reg, factory()->undefined_value()); | 5084 __ Cmp(input_reg, factory()->undefined_value()); |
| 5077 DeoptimizeIf(not_equal, instr->environment()); | 5085 DeoptimizeIf(not_equal, instr->environment()); |
| 5078 __ movq(input_reg, Immediate(0)); | 5086 __ movp(input_reg, Immediate(0)); |
| 5079 __ jmp(&done, Label::kNear); | 5087 __ jmp(&done, Label::kNear); |
| 5080 | 5088 |
| 5081 // Heap number | 5089 // Heap number |
| 5082 __ bind(&heap_number); | 5090 __ bind(&heap_number); |
| 5083 __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset)); | 5091 __ movsd(xmm_scratch, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| 5084 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg); | 5092 __ ClampDoubleToUint8(xmm_scratch, temp_xmm_reg, input_reg); |
| 5085 __ jmp(&done, Label::kNear); | 5093 __ jmp(&done, Label::kNear); |
| 5086 | 5094 |
| 5087 // smi | 5095 // smi |
| 5088 __ bind(&is_smi); | 5096 __ bind(&is_smi); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5203 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { | 5211 void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) { |
| 5204 ASSERT(ToRegister(instr->context()).is(rsi)); | 5212 ASSERT(ToRegister(instr->context()).is(rsi)); |
| 5205 Label materialized; | 5213 Label materialized; |
| 5206 // Registers will be used as follows: | 5214 // Registers will be used as follows: |
| 5207 // rcx = literals array. | 5215 // rcx = literals array. |
| 5208 // rbx = regexp literal. | 5216 // rbx = regexp literal. |
| 5209 // rax = regexp literal clone. | 5217 // rax = regexp literal clone. |
| 5210 int literal_offset = | 5218 int literal_offset = |
| 5211 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index()); | 5219 FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index()); |
| 5212 __ Move(rcx, instr->hydrogen()->literals()); | 5220 __ Move(rcx, instr->hydrogen()->literals()); |
| 5213 __ movq(rbx, FieldOperand(rcx, literal_offset)); | 5221 __ movp(rbx, FieldOperand(rcx, literal_offset)); |
| 5214 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); | 5222 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); |
| 5215 __ j(not_equal, &materialized, Label::kNear); | 5223 __ j(not_equal, &materialized, Label::kNear); |
| 5216 | 5224 |
| 5217 // Create regexp literal using runtime function | 5225 // Create regexp literal using runtime function |
| 5218 // Result will be in rax. | 5226 // Result will be in rax. |
| 5219 __ push(rcx); | 5227 __ push(rcx); |
| 5220 __ Push(Smi::FromInt(instr->hydrogen()->literal_index())); | 5228 __ Push(Smi::FromInt(instr->hydrogen()->literal_index())); |
| 5221 __ Push(instr->hydrogen()->pattern()); | 5229 __ Push(instr->hydrogen()->pattern()); |
| 5222 __ Push(instr->hydrogen()->flags()); | 5230 __ Push(instr->hydrogen()->flags()); |
| 5223 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr); | 5231 CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr); |
| 5224 __ movq(rbx, rax); | 5232 __ movp(rbx, rax); |
| 5225 | 5233 |
| 5226 __ bind(&materialized); | 5234 __ bind(&materialized); |
| 5227 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; | 5235 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; |
| 5228 Label allocated, runtime_allocate; | 5236 Label allocated, runtime_allocate; |
| 5229 __ Allocate(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT); | 5237 __ Allocate(size, rax, rcx, rdx, &runtime_allocate, TAG_OBJECT); |
| 5230 __ jmp(&allocated, Label::kNear); | 5238 __ jmp(&allocated, Label::kNear); |
| 5231 | 5239 |
| 5232 __ bind(&runtime_allocate); | 5240 __ bind(&runtime_allocate); |
| 5233 __ push(rbx); | 5241 __ push(rbx); |
| 5234 __ Push(Smi::FromInt(size)); | 5242 __ Push(Smi::FromInt(size)); |
| 5235 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr); | 5243 CallRuntime(Runtime::kAllocateInNewSpace, 1, instr); |
| 5236 __ pop(rbx); | 5244 __ pop(rbx); |
| 5237 | 5245 |
| 5238 __ bind(&allocated); | 5246 __ bind(&allocated); |
| 5239 // Copy the content into the newly allocated memory. | 5247 // Copy the content into the newly allocated memory. |
| 5240 // (Unroll copy loop once for better throughput). | 5248 // (Unroll copy loop once for better throughput). |
| 5241 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) { | 5249 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) { |
| 5242 __ movq(rdx, FieldOperand(rbx, i)); | 5250 __ movp(rdx, FieldOperand(rbx, i)); |
| 5243 __ movq(rcx, FieldOperand(rbx, i + kPointerSize)); | 5251 __ movp(rcx, FieldOperand(rbx, i + kPointerSize)); |
| 5244 __ movq(FieldOperand(rax, i), rdx); | 5252 __ movp(FieldOperand(rax, i), rdx); |
| 5245 __ movq(FieldOperand(rax, i + kPointerSize), rcx); | 5253 __ movp(FieldOperand(rax, i + kPointerSize), rcx); |
| 5246 } | 5254 } |
| 5247 if ((size % (2 * kPointerSize)) != 0) { | 5255 if ((size % (2 * kPointerSize)) != 0) { |
| 5248 __ movq(rdx, FieldOperand(rbx, size - kPointerSize)); | 5256 __ movp(rdx, FieldOperand(rbx, size - kPointerSize)); |
| 5249 __ movq(FieldOperand(rax, size - kPointerSize), rdx); | 5257 __ movp(FieldOperand(rax, size - kPointerSize), rdx); |
| 5250 } | 5258 } |
| 5251 } | 5259 } |
| 5252 | 5260 |
| 5253 | 5261 |
| 5254 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { | 5262 void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) { |
| 5255 ASSERT(ToRegister(instr->context()).is(rsi)); | 5263 ASSERT(ToRegister(instr->context()).is(rsi)); |
| 5256 // Use the fast case closure allocation code that allocates in new | 5264 // Use the fast case closure allocation code that allocates in new |
| 5257 // space for nested functions that don't need literals cloning. | 5265 // space for nested functions that don't need literals cloning. |
| 5258 bool pretenure = instr->hydrogen()->pretenure(); | 5266 bool pretenure = instr->hydrogen()->pretenure(); |
| 5259 if (!pretenure && instr->hydrogen()->has_no_literals()) { | 5267 if (!pretenure && instr->hydrogen()->has_no_literals()) { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5341 | 5349 |
| 5342 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) { | 5350 } else if (FLAG_harmony_typeof && type_name->Equals(heap()->null_string())) { |
| 5343 __ CompareRoot(input, Heap::kNullValueRootIndex); | 5351 __ CompareRoot(input, Heap::kNullValueRootIndex); |
| 5344 final_branch_condition = equal; | 5352 final_branch_condition = equal; |
| 5345 | 5353 |
| 5346 } else if (type_name->Equals(heap()->undefined_string())) { | 5354 } else if (type_name->Equals(heap()->undefined_string())) { |
| 5347 __ CompareRoot(input, Heap::kUndefinedValueRootIndex); | 5355 __ CompareRoot(input, Heap::kUndefinedValueRootIndex); |
| 5348 __ j(equal, true_label, true_distance); | 5356 __ j(equal, true_label, true_distance); |
| 5349 __ JumpIfSmi(input, false_label, false_distance); | 5357 __ JumpIfSmi(input, false_label, false_distance); |
| 5350 // Check for undetectable objects => true. | 5358 // Check for undetectable objects => true. |
| 5351 __ movq(input, FieldOperand(input, HeapObject::kMapOffset)); | 5359 __ movp(input, FieldOperand(input, HeapObject::kMapOffset)); |
| 5352 __ testb(FieldOperand(input, Map::kBitFieldOffset), | 5360 __ testb(FieldOperand(input, Map::kBitFieldOffset), |
| 5353 Immediate(1 << Map::kIsUndetectable)); | 5361 Immediate(1 << Map::kIsUndetectable)); |
| 5354 final_branch_condition = not_zero; | 5362 final_branch_condition = not_zero; |
| 5355 | 5363 |
| 5356 } else if (type_name->Equals(heap()->function_string())) { | 5364 } else if (type_name->Equals(heap()->function_string())) { |
| 5357 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); | 5365 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
| 5358 __ JumpIfSmi(input, false_label, false_distance); | 5366 __ JumpIfSmi(input, false_label, false_distance); |
| 5359 __ CmpObjectType(input, JS_FUNCTION_TYPE, input); | 5367 __ CmpObjectType(input, JS_FUNCTION_TYPE, input); |
| 5360 __ j(equal, true_label, true_distance); | 5368 __ j(equal, true_label, true_distance); |
| 5361 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE); | 5369 __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 5387 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { | 5395 void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) { |
| 5388 Register temp = ToRegister(instr->temp()); | 5396 Register temp = ToRegister(instr->temp()); |
| 5389 | 5397 |
| 5390 EmitIsConstructCall(temp); | 5398 EmitIsConstructCall(temp); |
| 5391 EmitBranch(instr, equal); | 5399 EmitBranch(instr, equal); |
| 5392 } | 5400 } |
| 5393 | 5401 |
| 5394 | 5402 |
| 5395 void LCodeGen::EmitIsConstructCall(Register temp) { | 5403 void LCodeGen::EmitIsConstructCall(Register temp) { |
| 5396 // Get the frame pointer for the calling frame. | 5404 // Get the frame pointer for the calling frame. |
| 5397 __ movq(temp, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 5405 __ movp(temp, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 5398 | 5406 |
| 5399 // Skip the arguments adaptor frame if it exists. | 5407 // Skip the arguments adaptor frame if it exists. |
| 5400 Label check_frame_marker; | 5408 Label check_frame_marker; |
| 5401 __ Cmp(Operand(temp, StandardFrameConstants::kContextOffset), | 5409 __ Cmp(Operand(temp, StandardFrameConstants::kContextOffset), |
| 5402 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 5410 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 5403 __ j(not_equal, &check_frame_marker, Label::kNear); | 5411 __ j(not_equal, &check_frame_marker, Label::kNear); |
| 5404 __ movq(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset)); | 5412 __ movp(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset)); |
| 5405 | 5413 |
| 5406 // Check the marker in the calling frame. | 5414 // Check the marker in the calling frame. |
| 5407 __ bind(&check_frame_marker); | 5415 __ bind(&check_frame_marker); |
| 5408 __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset), | 5416 __ Cmp(Operand(temp, StandardFrameConstants::kMarkerOffset), |
| 5409 Smi::FromInt(StackFrame::CONSTRUCT)); | 5417 Smi::FromInt(StackFrame::CONSTRUCT)); |
| 5410 } | 5418 } |
| 5411 | 5419 |
| 5412 | 5420 |
| 5413 void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) { | 5421 void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) { |
| 5414 if (!info()->IsStub()) { | 5422 if (!info()->IsStub()) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5453 } | 5461 } |
| 5454 | 5462 |
| 5455 | 5463 |
| 5456 void LCodeGen::DoDummyUse(LDummyUse* instr) { | 5464 void LCodeGen::DoDummyUse(LDummyUse* instr) { |
| 5457 // Nothing to see here, move on! | 5465 // Nothing to see here, move on! |
| 5458 } | 5466 } |
| 5459 | 5467 |
| 5460 | 5468 |
| 5461 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { | 5469 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) { |
| 5462 PushSafepointRegistersScope scope(this); | 5470 PushSafepointRegistersScope scope(this); |
| 5463 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 5471 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 5464 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); | 5472 __ CallRuntimeSaveDoubles(Runtime::kStackGuard); |
| 5465 RecordSafepointWithLazyDeopt(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0); | 5473 RecordSafepointWithLazyDeopt(instr, RECORD_SAFEPOINT_WITH_REGISTERS, 0); |
| 5466 ASSERT(instr->HasEnvironment()); | 5474 ASSERT(instr->HasEnvironment()); |
| 5467 LEnvironment* env = instr->environment(); | 5475 LEnvironment* env = instr->environment(); |
| 5468 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); | 5476 safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index()); |
| 5469 } | 5477 } |
| 5470 | 5478 |
| 5471 | 5479 |
| 5472 void LCodeGen::DoStackCheck(LStackCheck* instr) { | 5480 void LCodeGen::DoStackCheck(LStackCheck* instr) { |
| 5473 class DeferredStackCheck V8_FINAL : public LDeferredCode { | 5481 class DeferredStackCheck V8_FINAL : public LDeferredCode { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5547 Condition cc = masm()->CheckSmi(rax); | 5555 Condition cc = masm()->CheckSmi(rax); |
| 5548 DeoptimizeIf(cc, instr->environment()); | 5556 DeoptimizeIf(cc, instr->environment()); |
| 5549 | 5557 |
| 5550 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 5558 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 5551 __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx); | 5559 __ CmpObjectType(rax, LAST_JS_PROXY_TYPE, rcx); |
| 5552 DeoptimizeIf(below_equal, instr->environment()); | 5560 DeoptimizeIf(below_equal, instr->environment()); |
| 5553 | 5561 |
| 5554 Label use_cache, call_runtime; | 5562 Label use_cache, call_runtime; |
| 5555 __ CheckEnumCache(null_value, &call_runtime); | 5563 __ CheckEnumCache(null_value, &call_runtime); |
| 5556 | 5564 |
| 5557 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); | 5565 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
| 5558 __ jmp(&use_cache, Label::kNear); | 5566 __ jmp(&use_cache, Label::kNear); |
| 5559 | 5567 |
| 5560 // Get the set of properties to enumerate. | 5568 // Get the set of properties to enumerate. |
| 5561 __ bind(&call_runtime); | 5569 __ bind(&call_runtime); |
| 5562 __ push(rax); | 5570 __ push(rax); |
| 5563 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr); | 5571 CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr); |
| 5564 | 5572 |
| 5565 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | 5573 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
| 5566 Heap::kMetaMapRootIndex); | 5574 Heap::kMetaMapRootIndex); |
| 5567 DeoptimizeIf(not_equal, instr->environment()); | 5575 DeoptimizeIf(not_equal, instr->environment()); |
| 5568 __ bind(&use_cache); | 5576 __ bind(&use_cache); |
| 5569 } | 5577 } |
| 5570 | 5578 |
| 5571 | 5579 |
| 5572 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { | 5580 void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) { |
| 5573 Register map = ToRegister(instr->map()); | 5581 Register map = ToRegister(instr->map()); |
| 5574 Register result = ToRegister(instr->result()); | 5582 Register result = ToRegister(instr->result()); |
| 5575 Label load_cache, done; | 5583 Label load_cache, done; |
| 5576 __ EnumLength(result, map); | 5584 __ EnumLength(result, map); |
| 5577 __ Cmp(result, Smi::FromInt(0)); | 5585 __ Cmp(result, Smi::FromInt(0)); |
| 5578 __ j(not_equal, &load_cache, Label::kNear); | 5586 __ j(not_equal, &load_cache, Label::kNear); |
| 5579 __ LoadRoot(result, Heap::kEmptyFixedArrayRootIndex); | 5587 __ LoadRoot(result, Heap::kEmptyFixedArrayRootIndex); |
| 5580 __ jmp(&done, Label::kNear); | 5588 __ jmp(&done, Label::kNear); |
| 5581 __ bind(&load_cache); | 5589 __ bind(&load_cache); |
| 5582 __ LoadInstanceDescriptors(map, result); | 5590 __ LoadInstanceDescriptors(map, result); |
| 5583 __ movq(result, | 5591 __ movp(result, |
| 5584 FieldOperand(result, DescriptorArray::kEnumCacheOffset)); | 5592 FieldOperand(result, DescriptorArray::kEnumCacheOffset)); |
| 5585 __ movq(result, | 5593 __ movp(result, |
| 5586 FieldOperand(result, FixedArray::SizeFor(instr->idx()))); | 5594 FieldOperand(result, FixedArray::SizeFor(instr->idx()))); |
| 5587 __ bind(&done); | 5595 __ bind(&done); |
| 5588 Condition cc = masm()->CheckSmi(result); | 5596 Condition cc = masm()->CheckSmi(result); |
| 5589 DeoptimizeIf(cc, instr->environment()); | 5597 DeoptimizeIf(cc, instr->environment()); |
| 5590 } | 5598 } |
| 5591 | 5599 |
| 5592 | 5600 |
| 5593 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { | 5601 void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) { |
| 5594 Register object = ToRegister(instr->value()); | 5602 Register object = ToRegister(instr->value()); |
| 5595 __ cmpq(ToRegister(instr->map()), | 5603 __ cmpq(ToRegister(instr->map()), |
| 5596 FieldOperand(object, HeapObject::kMapOffset)); | 5604 FieldOperand(object, HeapObject::kMapOffset)); |
| 5597 DeoptimizeIf(not_equal, instr->environment()); | 5605 DeoptimizeIf(not_equal, instr->environment()); |
| 5598 } | 5606 } |
| 5599 | 5607 |
| 5600 | 5608 |
| 5601 void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) { | 5609 void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) { |
| 5602 Register object = ToRegister(instr->object()); | 5610 Register object = ToRegister(instr->object()); |
| 5603 Register index = ToRegister(instr->index()); | 5611 Register index = ToRegister(instr->index()); |
| 5604 | 5612 |
| 5605 Label out_of_object, done; | 5613 Label out_of_object, done; |
| 5606 __ SmiToInteger32(index, index); | 5614 __ SmiToInteger32(index, index); |
| 5607 __ cmpl(index, Immediate(0)); | 5615 __ cmpl(index, Immediate(0)); |
| 5608 __ j(less, &out_of_object, Label::kNear); | 5616 __ j(less, &out_of_object, Label::kNear); |
| 5609 __ movq(object, FieldOperand(object, | 5617 __ movp(object, FieldOperand(object, |
| 5610 index, | 5618 index, |
| 5611 times_pointer_size, | 5619 times_pointer_size, |
| 5612 JSObject::kHeaderSize)); | 5620 JSObject::kHeaderSize)); |
| 5613 __ jmp(&done, Label::kNear); | 5621 __ jmp(&done, Label::kNear); |
| 5614 | 5622 |
| 5615 __ bind(&out_of_object); | 5623 __ bind(&out_of_object); |
| 5616 __ movq(object, FieldOperand(object, JSObject::kPropertiesOffset)); | 5624 __ movp(object, FieldOperand(object, JSObject::kPropertiesOffset)); |
| 5617 __ negl(index); | 5625 __ negl(index); |
| 5618 // Index is now equal to out of object property index plus 1. | 5626 // Index is now equal to out of object property index plus 1. |
| 5619 __ movq(object, FieldOperand(object, | 5627 __ movp(object, FieldOperand(object, |
| 5620 index, | 5628 index, |
| 5621 times_pointer_size, | 5629 times_pointer_size, |
| 5622 FixedArray::kHeaderSize - kPointerSize)); | 5630 FixedArray::kHeaderSize - kPointerSize)); |
| 5623 __ bind(&done); | 5631 __ bind(&done); |
| 5624 } | 5632 } |
| 5625 | 5633 |
| 5626 | 5634 |
| 5627 #undef __ | 5635 #undef __ |
| 5628 | 5636 |
| 5629 } } // namespace v8::internal | 5637 } } // namespace v8::internal |
| 5630 | 5638 |
| 5631 #endif // V8_TARGET_ARCH_X64 | 5639 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |