OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 RegisterAllocator register_allocator(this); | 173 RegisterAllocator register_allocator(this); |
174 allocator_ = ®ister_allocator; | 174 allocator_ = ®ister_allocator; |
175 ASSERT(frame_ == NULL); | 175 ASSERT(frame_ == NULL); |
176 frame_ = new VirtualFrame(); | 176 frame_ = new VirtualFrame(); |
177 set_in_spilled_code(false); | 177 set_in_spilled_code(false); |
178 | 178 |
179 // Adjust for function-level loop nesting. | 179 // Adjust for function-level loop nesting. |
180 ASSERT_EQ(0, loop_nesting_); | 180 ASSERT_EQ(0, loop_nesting_); |
181 loop_nesting_ = info->is_in_loop() ? 1 : 0; | 181 loop_nesting_ = info->is_in_loop() ? 1 : 0; |
182 | 182 |
183 JumpTarget::set_compiling_deferred_code(false); | 183 Isolate::Current()->set_jump_target_compiling_deferred_code(false); |
184 | 184 |
185 { | 185 { |
186 CodeGenState state(this); | 186 CodeGenState state(this); |
187 // Entry: | 187 // Entry: |
188 // Stack: receiver, arguments, return address. | 188 // Stack: receiver, arguments, return address. |
189 // rbp: caller's frame pointer | 189 // rbp: caller's frame pointer |
190 // rsp: stack pointer | 190 // rsp: stack pointer |
191 // rdi: called JS function | 191 // rdi: called JS function |
192 // rsi: callee's context | 192 // rsi: callee's context |
193 allocator_->Initialize(); | 193 allocator_->Initialize(); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 | 274 |
275 // Store the arguments object. This must happen after context | 275 // Store the arguments object. This must happen after context |
276 // initialization because the arguments object may be stored in | 276 // initialization because the arguments object may be stored in |
277 // the context. | 277 // the context. |
278 if (ArgumentsMode() != NO_ARGUMENTS_ALLOCATION) { | 278 if (ArgumentsMode() != NO_ARGUMENTS_ALLOCATION) { |
279 StoreArgumentsObject(true); | 279 StoreArgumentsObject(true); |
280 } | 280 } |
281 | 281 |
282 // Initialize ThisFunction reference if present. | 282 // Initialize ThisFunction reference if present. |
283 if (scope()->is_function_scope() && scope()->function() != NULL) { | 283 if (scope()->is_function_scope() && scope()->function() != NULL) { |
284 frame_->Push(Factory::the_hole_value()); | 284 frame_->Push(FACTORY->the_hole_value()); |
285 StoreToSlot(scope()->function()->AsSlot(), NOT_CONST_INIT); | 285 StoreToSlot(scope()->function()->AsSlot(), NOT_CONST_INIT); |
286 } | 286 } |
287 | 287 |
288 // Initialize the function return target after the locals are set | 288 // Initialize the function return target after the locals are set |
289 // up, because it needs the expected frame height from the frame. | 289 // up, because it needs the expected frame height from the frame. |
290 function_return_.set_direction(JumpTarget::BIDIRECTIONAL); | 290 function_return_.set_direction(JumpTarget::BIDIRECTIONAL); |
291 function_return_is_shadowed_ = false; | 291 function_return_is_shadowed_ = false; |
292 | 292 |
293 // Generate code to 'execute' declarations and initialize functions | 293 // Generate code to 'execute' declarations and initialize functions |
294 // (source elements). In case of an illegal redeclaration we need to | 294 // (source elements). In case of an illegal redeclaration we need to |
(...skipping 14 matching lines...) Expand all Loading... |
309 // Ignore the return value. | 309 // Ignore the return value. |
310 } | 310 } |
311 CheckStack(); | 311 CheckStack(); |
312 | 312 |
313 // Compile the body of the function in a vanilla state. Don't | 313 // Compile the body of the function in a vanilla state. Don't |
314 // bother compiling all the code if the scope has an illegal | 314 // bother compiling all the code if the scope has an illegal |
315 // redeclaration. | 315 // redeclaration. |
316 if (!scope()->HasIllegalRedeclaration()) { | 316 if (!scope()->HasIllegalRedeclaration()) { |
317 Comment cmnt(masm_, "[ function body"); | 317 Comment cmnt(masm_, "[ function body"); |
318 #ifdef DEBUG | 318 #ifdef DEBUG |
319 bool is_builtin = Bootstrapper::IsActive(); | 319 bool is_builtin = Isolate::Current()->bootstrapper()->IsActive(); |
320 bool should_trace = | 320 bool should_trace = |
321 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; | 321 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; |
322 if (should_trace) { | 322 if (should_trace) { |
323 frame_->CallRuntime(Runtime::kDebugTrace, 0); | 323 frame_->CallRuntime(Runtime::kDebugTrace, 0); |
324 // Ignore the return value. | 324 // Ignore the return value. |
325 } | 325 } |
326 #endif | 326 #endif |
327 VisitStatements(info->function()->body()); | 327 VisitStatements(info->function()->body()); |
328 | 328 |
329 // Handle the return from the function. | 329 // Handle the return from the function. |
330 if (has_valid_frame()) { | 330 if (has_valid_frame()) { |
331 // If there is a valid frame, control flow can fall off the end of | 331 // If there is a valid frame, control flow can fall off the end of |
332 // the body. In that case there is an implicit return statement. | 332 // the body. In that case there is an implicit return statement. |
333 ASSERT(!function_return_is_shadowed_); | 333 ASSERT(!function_return_is_shadowed_); |
334 CodeForReturnPosition(info->function()); | 334 CodeForReturnPosition(info->function()); |
335 frame_->PrepareForReturn(); | 335 frame_->PrepareForReturn(); |
336 Result undefined(Factory::undefined_value()); | 336 Result undefined(FACTORY->undefined_value()); |
337 if (function_return_.is_bound()) { | 337 if (function_return_.is_bound()) { |
338 function_return_.Jump(&undefined); | 338 function_return_.Jump(&undefined); |
339 } else { | 339 } else { |
340 function_return_.Bind(&undefined); | 340 function_return_.Bind(&undefined); |
341 GenerateReturnSequence(&undefined); | 341 GenerateReturnSequence(&undefined); |
342 } | 342 } |
343 } else if (function_return_.is_linked()) { | 343 } else if (function_return_.is_linked()) { |
344 // If the return target has dangling jumps to it, then we have not | 344 // If the return target has dangling jumps to it, then we have not |
345 // yet generated the return sequence. This can happen when (a) | 345 // yet generated the return sequence. This can happen when (a) |
346 // control does not flow off the end of the body so we did not | 346 // control does not flow off the end of the body so we did not |
(...skipping 11 matching lines...) Expand all Loading... |
358 loop_nesting_ = 0; | 358 loop_nesting_ = 0; |
359 | 359 |
360 // Code generation state must be reset. | 360 // Code generation state must be reset. |
361 ASSERT(state_ == NULL); | 361 ASSERT(state_ == NULL); |
362 ASSERT(!function_return_is_shadowed_); | 362 ASSERT(!function_return_is_shadowed_); |
363 function_return_.Unuse(); | 363 function_return_.Unuse(); |
364 DeleteFrame(); | 364 DeleteFrame(); |
365 | 365 |
366 // Process any deferred code using the register allocator. | 366 // Process any deferred code using the register allocator. |
367 if (!HasStackOverflow()) { | 367 if (!HasStackOverflow()) { |
368 JumpTarget::set_compiling_deferred_code(true); | 368 info->isolate()->set_jump_target_compiling_deferred_code(true); |
369 ProcessDeferred(); | 369 ProcessDeferred(); |
370 JumpTarget::set_compiling_deferred_code(false); | 370 info->isolate()->set_jump_target_compiling_deferred_code(false); |
371 } | 371 } |
372 | 372 |
373 // There is no need to delete the register allocator, it is a | 373 // There is no need to delete the register allocator, it is a |
374 // stack-allocated local. | 374 // stack-allocated local. |
375 allocator_ = NULL; | 375 allocator_ = NULL; |
376 } | 376 } |
377 | 377 |
378 | 378 |
379 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 379 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { |
380 // Currently, this assertion will fail if we try to assign to | 380 // Currently, this assertion will fail if we try to assign to |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 #endif | 509 #endif |
510 ASSERT(!in_spilled_code()); | 510 ASSERT(!in_spilled_code()); |
511 JumpTarget true_target; | 511 JumpTarget true_target; |
512 JumpTarget false_target; | 512 JumpTarget false_target; |
513 ControlDestination dest(&true_target, &false_target, true); | 513 ControlDestination dest(&true_target, &false_target, true); |
514 LoadCondition(expr, &dest, false); | 514 LoadCondition(expr, &dest, false); |
515 | 515 |
516 if (dest.false_was_fall_through()) { | 516 if (dest.false_was_fall_through()) { |
517 // The false target was just bound. | 517 // The false target was just bound. |
518 JumpTarget loaded; | 518 JumpTarget loaded; |
519 frame_->Push(Factory::false_value()); | 519 frame_->Push(FACTORY->false_value()); |
520 // There may be dangling jumps to the true target. | 520 // There may be dangling jumps to the true target. |
521 if (true_target.is_linked()) { | 521 if (true_target.is_linked()) { |
522 loaded.Jump(); | 522 loaded.Jump(); |
523 true_target.Bind(); | 523 true_target.Bind(); |
524 frame_->Push(Factory::true_value()); | 524 frame_->Push(FACTORY->true_value()); |
525 loaded.Bind(); | 525 loaded.Bind(); |
526 } | 526 } |
527 | 527 |
528 } else if (dest.is_used()) { | 528 } else if (dest.is_used()) { |
529 // There is true, and possibly false, control flow (with true as | 529 // There is true, and possibly false, control flow (with true as |
530 // the fall through). | 530 // the fall through). |
531 JumpTarget loaded; | 531 JumpTarget loaded; |
532 frame_->Push(Factory::true_value()); | 532 frame_->Push(FACTORY->true_value()); |
533 if (false_target.is_linked()) { | 533 if (false_target.is_linked()) { |
534 loaded.Jump(); | 534 loaded.Jump(); |
535 false_target.Bind(); | 535 false_target.Bind(); |
536 frame_->Push(Factory::false_value()); | 536 frame_->Push(FACTORY->false_value()); |
537 loaded.Bind(); | 537 loaded.Bind(); |
538 } | 538 } |
539 | 539 |
540 } else { | 540 } else { |
541 // We have a valid value on top of the frame, but we still may | 541 // We have a valid value on top of the frame, but we still may |
542 // have dangling jumps to the true and false targets from nested | 542 // have dangling jumps to the true and false targets from nested |
543 // subexpressions (eg, the left subexpressions of the | 543 // subexpressions (eg, the left subexpressions of the |
544 // short-circuited boolean operators). | 544 // short-circuited boolean operators). |
545 ASSERT(has_valid_frame()); | 545 ASSERT(has_valid_frame()); |
546 if (true_target.is_linked() || false_target.is_linked()) { | 546 if (true_target.is_linked() || false_target.is_linked()) { |
547 JumpTarget loaded; | 547 JumpTarget loaded; |
548 loaded.Jump(); // Don't lose the current TOS. | 548 loaded.Jump(); // Don't lose the current TOS. |
549 if (true_target.is_linked()) { | 549 if (true_target.is_linked()) { |
550 true_target.Bind(); | 550 true_target.Bind(); |
551 frame_->Push(Factory::true_value()); | 551 frame_->Push(FACTORY->true_value()); |
552 if (false_target.is_linked()) { | 552 if (false_target.is_linked()) { |
553 loaded.Jump(); | 553 loaded.Jump(); |
554 } | 554 } |
555 } | 555 } |
556 if (false_target.is_linked()) { | 556 if (false_target.is_linked()) { |
557 false_target.Bind(); | 557 false_target.Bind(); |
558 frame_->Push(Factory::false_value()); | 558 frame_->Push(FACTORY->false_value()); |
559 } | 559 } |
560 loaded.Bind(); | 560 loaded.Bind(); |
561 } | 561 } |
562 } | 562 } |
563 | 563 |
564 ASSERT(has_valid_frame()); | 564 ASSERT(has_valid_frame()); |
565 ASSERT(frame_->height() == original_height + 1); | 565 ASSERT(frame_->height() == original_height + 1); |
566 } | 566 } |
567 | 567 |
568 | 568 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
625 | 625 |
626 Result CodeGenerator::StoreArgumentsObject(bool initial) { | 626 Result CodeGenerator::StoreArgumentsObject(bool initial) { |
627 ArgumentsAllocationMode mode = ArgumentsMode(); | 627 ArgumentsAllocationMode mode = ArgumentsMode(); |
628 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); | 628 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); |
629 | 629 |
630 Comment cmnt(masm_, "[ store arguments object"); | 630 Comment cmnt(masm_, "[ store arguments object"); |
631 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { | 631 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { |
632 // When using lazy arguments allocation, we store the arguments marker value | 632 // When using lazy arguments allocation, we store the arguments marker value |
633 // as a sentinel indicating that the arguments object hasn't been | 633 // as a sentinel indicating that the arguments object hasn't been |
634 // allocated yet. | 634 // allocated yet. |
635 frame_->Push(Factory::arguments_marker()); | 635 frame_->Push(FACTORY->arguments_marker()); |
636 } else { | 636 } else { |
637 ArgumentsAccessStub stub(is_strict_mode() | 637 ArgumentsAccessStub stub(is_strict_mode() |
638 ? ArgumentsAccessStub::NEW_STRICT | 638 ? ArgumentsAccessStub::NEW_STRICT |
639 : ArgumentsAccessStub::NEW_NON_STRICT); | 639 : ArgumentsAccessStub::NEW_NON_STRICT); |
640 frame_->PushFunction(); | 640 frame_->PushFunction(); |
641 frame_->PushReceiverSlotAddress(); | 641 frame_->PushReceiverSlotAddress(); |
642 frame_->Push(Smi::FromInt(scope()->num_parameters())); | 642 frame_->Push(Smi::FromInt(scope()->num_parameters())); |
643 Result result = frame_->CallStub(&stub, 3); | 643 Result result = frame_->CallStub(&stub, 3); |
644 frame_->Push(&result); | 644 frame_->Push(&result); |
645 } | 645 } |
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1055 answer = GenerateGenericBinaryOpStubCall(&stub, &left, &right); | 1055 answer = GenerateGenericBinaryOpStubCall(&stub, &left, &right); |
1056 } | 1056 } |
1057 } | 1057 } |
1058 | 1058 |
1059 answer.set_type_info(result_type); | 1059 answer.set_type_info(result_type); |
1060 frame_->Push(&answer); | 1060 frame_->Push(&answer); |
1061 } | 1061 } |
1062 | 1062 |
1063 | 1063 |
1064 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { | 1064 bool CodeGenerator::FoldConstantSmis(Token::Value op, int left, int right) { |
1065 Object* answer_object = Heap::undefined_value(); | 1065 Object* answer_object = HEAP->undefined_value(); |
1066 switch (op) { | 1066 switch (op) { |
1067 case Token::ADD: | 1067 case Token::ADD: |
1068 // Use intptr_t to detect overflow of 32-bit int. | 1068 // Use intptr_t to detect overflow of 32-bit int. |
1069 if (Smi::IsValid(static_cast<intptr_t>(left) + right)) { | 1069 if (Smi::IsValid(static_cast<intptr_t>(left) + right)) { |
1070 answer_object = Smi::FromInt(left + right); | 1070 answer_object = Smi::FromInt(left + right); |
1071 } | 1071 } |
1072 break; | 1072 break; |
1073 case Token::SUB: | 1073 case Token::SUB: |
1074 // Use intptr_t to detect overflow of 32-bit int. | 1074 // Use intptr_t to detect overflow of 32-bit int. |
1075 if (Smi::IsValid(static_cast<intptr_t>(left) - right)) { | 1075 if (Smi::IsValid(static_cast<intptr_t>(left) - right)) { |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1129 unsigned_left >>= shift_amount; | 1129 unsigned_left >>= shift_amount; |
1130 } | 1130 } |
1131 ASSERT(Smi::IsValid(static_cast<int32_t>(unsigned_left))); | 1131 ASSERT(Smi::IsValid(static_cast<int32_t>(unsigned_left))); |
1132 answer_object = Smi::FromInt(static_cast<int32_t>(unsigned_left)); | 1132 answer_object = Smi::FromInt(static_cast<int32_t>(unsigned_left)); |
1133 break; | 1133 break; |
1134 } | 1134 } |
1135 default: | 1135 default: |
1136 UNREACHABLE(); | 1136 UNREACHABLE(); |
1137 break; | 1137 break; |
1138 } | 1138 } |
1139 if (answer_object == Heap::undefined_value()) { | 1139 if (answer_object->IsUndefined()) { |
1140 return false; | 1140 return false; |
1141 } | 1141 } |
1142 frame_->Push(Handle<Object>(answer_object)); | 1142 frame_->Push(Handle<Object>(answer_object)); |
1143 return true; | 1143 return true; |
1144 } | 1144 } |
1145 | 1145 |
1146 | 1146 |
1147 void CodeGenerator::JumpIfBothSmiUsingTypeInfo(Result* left, | 1147 void CodeGenerator::JumpIfBothSmiUsingTypeInfo(Result* left, |
1148 Result* right, | 1148 Result* right, |
1149 JumpTarget* both_smi) { | 1149 JumpTarget* both_smi) { |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1364 __ AbortIfNotSmi(right->reg()); | 1364 __ AbortIfNotSmi(right->reg()); |
1365 } | 1365 } |
1366 // If left is not known to be a smi, check if it is. | 1366 // If left is not known to be a smi, check if it is. |
1367 // If left is not known to be a number, and it isn't a smi, check if | 1367 // If left is not known to be a number, and it isn't a smi, check if |
1368 // it is a HeapNumber. | 1368 // it is a HeapNumber. |
1369 if (!left_type_info.IsSmi()) { | 1369 if (!left_type_info.IsSmi()) { |
1370 __ JumpIfSmi(answer.reg(), &do_op); | 1370 __ JumpIfSmi(answer.reg(), &do_op); |
1371 if (!left_type_info.IsNumber()) { | 1371 if (!left_type_info.IsNumber()) { |
1372 // Branch if not a heapnumber. | 1372 // Branch if not a heapnumber. |
1373 __ Cmp(FieldOperand(answer.reg(), HeapObject::kMapOffset), | 1373 __ Cmp(FieldOperand(answer.reg(), HeapObject::kMapOffset), |
1374 Factory::heap_number_map()); | 1374 FACTORY->heap_number_map()); |
1375 deferred->Branch(not_equal); | 1375 deferred->Branch(not_equal); |
1376 } | 1376 } |
1377 // Load integer value into answer register using truncation. | 1377 // Load integer value into answer register using truncation. |
1378 __ cvttsd2si(answer.reg(), | 1378 __ cvttsd2si(answer.reg(), |
1379 FieldOperand(answer.reg(), HeapNumber::kValueOffset)); | 1379 FieldOperand(answer.reg(), HeapNumber::kValueOffset)); |
1380 // Branch if we might have overflowed. | 1380 // Branch if we might have overflowed. |
1381 // (False negative for Smi::kMinValue) | 1381 // (False negative for Smi::kMinValue) |
1382 __ cmpl(answer.reg(), Immediate(0x80000000)); | 1382 __ cmpl(answer.reg(), Immediate(0x80000000)); |
1383 deferred->Branch(equal); | 1383 deferred->Branch(equal); |
1384 // TODO(lrn): Inline shifts on int32 here instead of first smi-tagging. | 1384 // TODO(lrn): Inline shifts on int32 here instead of first smi-tagging. |
(...skipping 941 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2326 } | 2326 } |
2327 | 2327 |
2328 // Jump or fall through to here if we are comparing a non-smi to a | 2328 // Jump or fall through to here if we are comparing a non-smi to a |
2329 // constant smi. If the non-smi is a heap number and this is not | 2329 // constant smi. If the non-smi is a heap number and this is not |
2330 // a loop condition, inline the floating point code. | 2330 // a loop condition, inline the floating point code. |
2331 if (!is_loop_condition) { | 2331 if (!is_loop_condition) { |
2332 // Right side is a constant smi and left side has been checked | 2332 // Right side is a constant smi and left side has been checked |
2333 // not to be a smi. | 2333 // not to be a smi. |
2334 JumpTarget not_number; | 2334 JumpTarget not_number; |
2335 __ Cmp(FieldOperand(left_reg, HeapObject::kMapOffset), | 2335 __ Cmp(FieldOperand(left_reg, HeapObject::kMapOffset), |
2336 Factory::heap_number_map()); | 2336 FACTORY->heap_number_map()); |
2337 not_number.Branch(not_equal, left_side); | 2337 not_number.Branch(not_equal, left_side); |
2338 __ movsd(xmm1, | 2338 __ movsd(xmm1, |
2339 FieldOperand(left_reg, HeapNumber::kValueOffset)); | 2339 FieldOperand(left_reg, HeapNumber::kValueOffset)); |
2340 int value = constant_smi->value(); | 2340 int value = constant_smi->value(); |
2341 if (value == 0) { | 2341 if (value == 0) { |
2342 __ xorpd(xmm0, xmm0); | 2342 __ xorpd(xmm0, xmm0); |
2343 } else { | 2343 } else { |
2344 Result temp = allocator()->Allocate(); | 2344 Result temp = allocator()->Allocate(); |
2345 __ movl(temp.reg(), Immediate(value)); | 2345 __ movl(temp.reg(), Immediate(value)); |
2346 __ cvtlsi2sd(xmm0, temp.reg()); | 2346 __ cvtlsi2sd(xmm0, temp.reg()); |
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2486 // stack, as receiver and arguments, and calls x. | 2486 // stack, as receiver and arguments, and calls x. |
2487 // In the implementation comments, we call x the applicand | 2487 // In the implementation comments, we call x the applicand |
2488 // and y the receiver. | 2488 // and y the receiver. |
2489 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); | 2489 ASSERT(ArgumentsMode() == LAZY_ARGUMENTS_ALLOCATION); |
2490 ASSERT(arguments->IsArguments()); | 2490 ASSERT(arguments->IsArguments()); |
2491 | 2491 |
2492 // Load applicand.apply onto the stack. This will usually | 2492 // Load applicand.apply onto the stack. This will usually |
2493 // give us a megamorphic load site. Not super, but it works. | 2493 // give us a megamorphic load site. Not super, but it works. |
2494 Load(applicand); | 2494 Load(applicand); |
2495 frame()->Dup(); | 2495 frame()->Dup(); |
2496 Handle<String> name = Factory::LookupAsciiSymbol("apply"); | 2496 Handle<String> name = FACTORY->LookupAsciiSymbol("apply"); |
2497 frame()->Push(name); | 2497 frame()->Push(name); |
2498 Result answer = frame()->CallLoadIC(RelocInfo::CODE_TARGET); | 2498 Result answer = frame()->CallLoadIC(RelocInfo::CODE_TARGET); |
2499 __ nop(); | 2499 __ nop(); |
2500 frame()->Push(&answer); | 2500 frame()->Push(&answer); |
2501 | 2501 |
2502 // Load the receiver and the existing arguments object onto the | 2502 // Load the receiver and the existing arguments object onto the |
2503 // expression stack. Avoid allocating the arguments object here. | 2503 // expression stack. Avoid allocating the arguments object here. |
2504 Load(receiver); | 2504 Load(receiver); |
2505 LoadFromSlot(scope()->arguments()->AsSlot(), NOT_INSIDE_TYPEOF); | 2505 LoadFromSlot(scope()->arguments()->AsSlot(), NOT_INSIDE_TYPEOF); |
2506 | 2506 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2554 __ j(below, &build_args); | 2554 __ j(below, &build_args); |
2555 | 2555 |
2556 // Check that applicand.apply is Function.prototype.apply. | 2556 // Check that applicand.apply is Function.prototype.apply. |
2557 __ movq(rax, Operand(rsp, kPointerSize)); | 2557 __ movq(rax, Operand(rsp, kPointerSize)); |
2558 is_smi = masm_->CheckSmi(rax); | 2558 is_smi = masm_->CheckSmi(rax); |
2559 __ j(is_smi, &build_args); | 2559 __ j(is_smi, &build_args); |
2560 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rcx); | 2560 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rcx); |
2561 __ j(not_equal, &build_args); | 2561 __ j(not_equal, &build_args); |
2562 __ movq(rcx, FieldOperand(rax, JSFunction::kCodeEntryOffset)); | 2562 __ movq(rcx, FieldOperand(rax, JSFunction::kCodeEntryOffset)); |
2563 __ subq(rcx, Immediate(Code::kHeaderSize - kHeapObjectTag)); | 2563 __ subq(rcx, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
2564 Handle<Code> apply_code(Builtins::builtin(Builtins::FunctionApply)); | 2564 Handle<Code> apply_code(Isolate::Current()->builtins()->builtin( |
| 2565 Builtins::FunctionApply)); |
2565 __ Cmp(rcx, apply_code); | 2566 __ Cmp(rcx, apply_code); |
2566 __ j(not_equal, &build_args); | 2567 __ j(not_equal, &build_args); |
2567 | 2568 |
2568 // Check that applicand is a function. | 2569 // Check that applicand is a function. |
2569 __ movq(rdi, Operand(rsp, 2 * kPointerSize)); | 2570 __ movq(rdi, Operand(rsp, 2 * kPointerSize)); |
2570 is_smi = masm_->CheckSmi(rdi); | 2571 is_smi = masm_->CheckSmi(rdi); |
2571 __ j(is_smi, &build_args); | 2572 __ j(is_smi, &build_args); |
2572 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | 2573 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
2573 __ j(not_equal, &build_args); | 2574 __ j(not_equal, &build_args); |
2574 | 2575 |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2797 Result ignored = frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); | 2798 Result ignored = frame_->CallRuntime(Runtime::kDeclareContextSlot, 4); |
2798 // Ignore the return value (declarations are statements). | 2799 // Ignore the return value (declarations are statements). |
2799 return; | 2800 return; |
2800 } | 2801 } |
2801 | 2802 |
2802 ASSERT(!var->is_global()); | 2803 ASSERT(!var->is_global()); |
2803 | 2804 |
2804 // If we have a function or a constant, we need to initialize the variable. | 2805 // If we have a function or a constant, we need to initialize the variable. |
2805 Expression* val = NULL; | 2806 Expression* val = NULL; |
2806 if (node->mode() == Variable::CONST) { | 2807 if (node->mode() == Variable::CONST) { |
2807 val = new Literal(Factory::the_hole_value()); | 2808 val = new Literal(FACTORY->the_hole_value()); |
2808 } else { | 2809 } else { |
2809 val = node->fun(); // NULL if we don't have a function | 2810 val = node->fun(); // NULL if we don't have a function |
2810 } | 2811 } |
2811 | 2812 |
2812 if (val != NULL) { | 2813 if (val != NULL) { |
2813 { | 2814 { |
2814 // Set the initial value. | 2815 // Set the initial value. |
2815 Reference target(this, node->proxy()); | 2816 Reference target(this, node->proxy()); |
2816 Load(val); | 2817 Load(val); |
2817 target.SetValue(NOT_CONST_INIT); | 2818 target.SetValue(NOT_CONST_INIT); |
(...skipping 1155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3973 // After shadowing stops, the original targets are unshadowed and the | 3974 // After shadowing stops, the original targets are unshadowed and the |
3974 // ShadowTargets represent the formerly shadowing targets. | 3975 // ShadowTargets represent the formerly shadowing targets. |
3975 bool has_unlinks = false; | 3976 bool has_unlinks = false; |
3976 for (int i = 0; i < shadows.length(); i++) { | 3977 for (int i = 0; i < shadows.length(); i++) { |
3977 shadows[i]->StopShadowing(); | 3978 shadows[i]->StopShadowing(); |
3978 has_unlinks = has_unlinks || shadows[i]->is_linked(); | 3979 has_unlinks = has_unlinks || shadows[i]->is_linked(); |
3979 } | 3980 } |
3980 function_return_is_shadowed_ = function_return_was_shadowed; | 3981 function_return_is_shadowed_ = function_return_was_shadowed; |
3981 | 3982 |
3982 // Get an external reference to the handler address. | 3983 // Get an external reference to the handler address. |
3983 ExternalReference handler_address(Top::k_handler_address); | 3984 ExternalReference handler_address(Isolate::k_handler_address); |
3984 | 3985 |
3985 // Make sure that there's nothing left on the stack above the | 3986 // Make sure that there's nothing left on the stack above the |
3986 // handler structure. | 3987 // handler structure. |
3987 if (FLAG_debug_code) { | 3988 if (FLAG_debug_code) { |
3988 __ movq(kScratchRegister, handler_address); | 3989 __ movq(kScratchRegister, handler_address); |
3989 __ cmpq(rsp, Operand(kScratchRegister, 0)); | 3990 __ cmpq(rsp, Operand(kScratchRegister, 0)); |
3990 __ Assert(equal, "stack pointer should point to top handler"); | 3991 __ Assert(equal, "stack pointer should point to top handler"); |
3991 } | 3992 } |
3992 | 3993 |
3993 // If we can fall off the end of the try block, unlink from try chain. | 3994 // If we can fall off the end of the try block, unlink from try chain. |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4102 // After shadowing stops, the original targets are unshadowed and the | 4103 // After shadowing stops, the original targets are unshadowed and the |
4103 // ShadowTargets represent the formerly shadowing targets. | 4104 // ShadowTargets represent the formerly shadowing targets. |
4104 int nof_unlinks = 0; | 4105 int nof_unlinks = 0; |
4105 for (int i = 0; i < shadows.length(); i++) { | 4106 for (int i = 0; i < shadows.length(); i++) { |
4106 shadows[i]->StopShadowing(); | 4107 shadows[i]->StopShadowing(); |
4107 if (shadows[i]->is_linked()) nof_unlinks++; | 4108 if (shadows[i]->is_linked()) nof_unlinks++; |
4108 } | 4109 } |
4109 function_return_is_shadowed_ = function_return_was_shadowed; | 4110 function_return_is_shadowed_ = function_return_was_shadowed; |
4110 | 4111 |
4111 // Get an external reference to the handler address. | 4112 // Get an external reference to the handler address. |
4112 ExternalReference handler_address(Top::k_handler_address); | 4113 ExternalReference handler_address(Isolate::k_handler_address); |
4113 | 4114 |
4114 // If we can fall off the end of the try block, unlink from the try | 4115 // If we can fall off the end of the try block, unlink from the try |
4115 // chain and set the state on the frame to FALLING. | 4116 // chain and set the state on the frame to FALLING. |
4116 if (has_valid_frame()) { | 4117 if (has_valid_frame()) { |
4117 // The next handler address is on top of the frame. | 4118 // The next handler address is on top of the frame. |
4118 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); | 4119 STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
4119 __ movq(kScratchRegister, handler_address); | 4120 __ movq(kScratchRegister, handler_address); |
4120 frame_->EmitPop(Operand(kScratchRegister, 0)); | 4121 frame_->EmitPop(Operand(kScratchRegister, 0)); |
4121 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); | 4122 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); |
4122 | 4123 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4269 function_info->strict_mode() ? kStrictMode : kNonStrictMode); | 4270 function_info->strict_mode() ? kStrictMode : kNonStrictMode); |
4270 frame_->Push(function_info); | 4271 frame_->Push(function_info); |
4271 Result answer = frame_->CallStub(&stub, 1); | 4272 Result answer = frame_->CallStub(&stub, 1); |
4272 frame_->Push(&answer); | 4273 frame_->Push(&answer); |
4273 } else { | 4274 } else { |
4274 // Call the runtime to instantiate the function based on the | 4275 // Call the runtime to instantiate the function based on the |
4275 // shared function info. | 4276 // shared function info. |
4276 frame_->EmitPush(rsi); | 4277 frame_->EmitPush(rsi); |
4277 frame_->EmitPush(function_info); | 4278 frame_->EmitPush(function_info); |
4278 frame_->EmitPush(pretenure | 4279 frame_->EmitPush(pretenure |
4279 ? Factory::true_value() | 4280 ? FACTORY->true_value() |
4280 : Factory::false_value()); | 4281 : FACTORY->false_value()); |
4281 Result result = frame_->CallRuntime(Runtime::kNewClosure, 3); | 4282 Result result = frame_->CallRuntime(Runtime::kNewClosure, 3); |
4282 frame_->Push(&result); | 4283 frame_->Push(&result); |
4283 } | 4284 } |
4284 } | 4285 } |
4285 | 4286 |
4286 | 4287 |
4287 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 4288 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
4288 Comment cmnt(masm_, "[ FunctionLiteral"); | 4289 Comment cmnt(masm_, "[ FunctionLiteral"); |
4289 | 4290 |
4290 // Build the function info and instantiate it. | 4291 // Build the function info and instantiate it. |
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4755 if (!boilerplate_.is(rax)) __ movq(boilerplate_, rax); | 4756 if (!boilerplate_.is(rax)) __ movq(boilerplate_, rax); |
4756 } | 4757 } |
4757 | 4758 |
4758 | 4759 |
4759 class DeferredAllocateInNewSpace: public DeferredCode { | 4760 class DeferredAllocateInNewSpace: public DeferredCode { |
4760 public: | 4761 public: |
4761 DeferredAllocateInNewSpace(int size, | 4762 DeferredAllocateInNewSpace(int size, |
4762 Register target, | 4763 Register target, |
4763 int registers_to_save = 0) | 4764 int registers_to_save = 0) |
4764 : size_(size), target_(target), registers_to_save_(registers_to_save) { | 4765 : size_(size), target_(target), registers_to_save_(registers_to_save) { |
4765 ASSERT(size >= kPointerSize && size <= Heap::MaxObjectSizeInNewSpace()); | 4766 ASSERT(size >= kPointerSize && size <= HEAP->MaxObjectSizeInNewSpace()); |
4766 set_comment("[ DeferredAllocateInNewSpace"); | 4767 set_comment("[ DeferredAllocateInNewSpace"); |
4767 } | 4768 } |
4768 void Generate(); | 4769 void Generate(); |
4769 | 4770 |
4770 private: | 4771 private: |
4771 int size_; | 4772 int size_; |
4772 Register target_; | 4773 Register target_; |
4773 int registers_to_save_; | 4774 int registers_to_save_; |
4774 }; | 4775 }; |
4775 | 4776 |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4970 | 4971 |
4971 // Load the literals array of the function. | 4972 // Load the literals array of the function. |
4972 __ movq(literals.reg(), | 4973 __ movq(literals.reg(), |
4973 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); | 4974 FieldOperand(literals.reg(), JSFunction::kLiteralsOffset)); |
4974 | 4975 |
4975 frame_->Push(&literals); | 4976 frame_->Push(&literals); |
4976 frame_->Push(Smi::FromInt(node->literal_index())); | 4977 frame_->Push(Smi::FromInt(node->literal_index())); |
4977 frame_->Push(node->constant_elements()); | 4978 frame_->Push(node->constant_elements()); |
4978 int length = node->values()->length(); | 4979 int length = node->values()->length(); |
4979 Result clone; | 4980 Result clone; |
4980 if (node->constant_elements()->map() == Heap::fixed_cow_array_map()) { | 4981 if (node->constant_elements()->map() == HEAP->fixed_cow_array_map()) { |
4981 FastCloneShallowArrayStub stub( | 4982 FastCloneShallowArrayStub stub( |
4982 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length); | 4983 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length); |
4983 clone = frame_->CallStub(&stub, 3); | 4984 clone = frame_->CallStub(&stub, 3); |
4984 __ IncrementCounter(&Counters::cow_arrays_created_stub, 1); | 4985 __ IncrementCounter(COUNTERS->cow_arrays_created_stub(), 1); |
4985 } else if (node->depth() > 1) { | 4986 } else if (node->depth() > 1) { |
4986 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3); | 4987 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteral, 3); |
4987 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { | 4988 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) { |
4988 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); | 4989 clone = frame_->CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); |
4989 } else { | 4990 } else { |
4990 FastCloneShallowArrayStub stub( | 4991 FastCloneShallowArrayStub stub( |
4991 FastCloneShallowArrayStub::CLONE_ELEMENTS, length); | 4992 FastCloneShallowArrayStub::CLONE_ELEMENTS, length); |
4992 clone = frame_->CallStub(&stub, 3); | 4993 clone = frame_->CallStub(&stub, 3); |
4993 } | 4994 } |
4994 frame_->Push(&clone); | 4995 frame_->Push(&clone); |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5372 | 5373 |
5373 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 5374 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
5374 // resolve the function we need to call and the receiver of the | 5375 // resolve the function we need to call and the receiver of the |
5375 // call. Then we call the resolved function using the given | 5376 // call. Then we call the resolved function using the given |
5376 // arguments. | 5377 // arguments. |
5377 | 5378 |
5378 // Prepare the stack for the call to the resolved function. | 5379 // Prepare the stack for the call to the resolved function. |
5379 Load(function); | 5380 Load(function); |
5380 | 5381 |
5381 // Allocate a frame slot for the receiver. | 5382 // Allocate a frame slot for the receiver. |
5382 frame_->Push(Factory::undefined_value()); | 5383 frame_->Push(FACTORY->undefined_value()); |
5383 | 5384 |
5384 // Load the arguments. | 5385 // Load the arguments. |
5385 int arg_count = args->length(); | 5386 int arg_count = args->length(); |
5386 for (int i = 0; i < arg_count; i++) { | 5387 for (int i = 0; i < arg_count; i++) { |
5387 Load(args->at(i)); | 5388 Load(args->at(i)); |
5388 frame_->SpillTop(); | 5389 frame_->SpillTop(); |
5389 } | 5390 } |
5390 | 5391 |
5391 // Result to hold the result of the function resolution and the | 5392 // Result to hold the result of the function resolution and the |
5392 // final result of the eval call. | 5393 // final result of the eval call. |
(...skipping 11 matching lines...) Expand all Loading... |
5404 // ResolvePossiblyDirectEvalNoLookup by pushing the loaded | 5405 // ResolvePossiblyDirectEvalNoLookup by pushing the loaded |
5405 // function, the first argument to the eval call and the | 5406 // function, the first argument to the eval call and the |
5406 // receiver. | 5407 // receiver. |
5407 Result fun = LoadFromGlobalSlotCheckExtensions(var->AsSlot(), | 5408 Result fun = LoadFromGlobalSlotCheckExtensions(var->AsSlot(), |
5408 NOT_INSIDE_TYPEOF, | 5409 NOT_INSIDE_TYPEOF, |
5409 &slow); | 5410 &slow); |
5410 frame_->Push(&fun); | 5411 frame_->Push(&fun); |
5411 if (arg_count > 0) { | 5412 if (arg_count > 0) { |
5412 frame_->PushElementAt(arg_count); | 5413 frame_->PushElementAt(arg_count); |
5413 } else { | 5414 } else { |
5414 frame_->Push(Factory::undefined_value()); | 5415 frame_->Push(FACTORY->undefined_value()); |
5415 } | 5416 } |
5416 frame_->PushParameterAt(-1); | 5417 frame_->PushParameterAt(-1); |
5417 | 5418 |
5418 // Push the strict mode flag. | 5419 // Push the strict mode flag. |
5419 frame_->Push(Smi::FromInt(strict_mode_flag())); | 5420 frame_->Push(Smi::FromInt(strict_mode_flag())); |
5420 | 5421 |
5421 // Resolve the call. | 5422 // Resolve the call. |
5422 result = | 5423 result = |
5423 frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 4); | 5424 frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 4); |
5424 | 5425 |
5425 done.Jump(&result); | 5426 done.Jump(&result); |
5426 slow.Bind(); | 5427 slow.Bind(); |
5427 } | 5428 } |
5428 | 5429 |
5429 // Prepare the stack for the call to ResolvePossiblyDirectEval by | 5430 // Prepare the stack for the call to ResolvePossiblyDirectEval by |
5430 // pushing the loaded function, the first argument to the eval | 5431 // pushing the loaded function, the first argument to the eval |
5431 // call and the receiver. | 5432 // call and the receiver. |
5432 frame_->PushElementAt(arg_count + 1); | 5433 frame_->PushElementAt(arg_count + 1); |
5433 if (arg_count > 0) { | 5434 if (arg_count > 0) { |
5434 frame_->PushElementAt(arg_count); | 5435 frame_->PushElementAt(arg_count); |
5435 } else { | 5436 } else { |
5436 frame_->Push(Factory::undefined_value()); | 5437 frame_->Push(FACTORY->undefined_value()); |
5437 } | 5438 } |
5438 frame_->PushParameterAt(-1); | 5439 frame_->PushParameterAt(-1); |
5439 | 5440 |
5440 // Push the strict mode flag. | 5441 // Push the strict mode flag. |
5441 frame_->Push(Smi::FromInt(strict_mode_flag())); | 5442 frame_->Push(Smi::FromInt(strict_mode_flag())); |
5442 | 5443 |
5443 // Resolve the call. | 5444 // Resolve the call. |
5444 result = frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 4); | 5445 result = frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 4); |
5445 | 5446 |
5446 // If we generated fast-case code bind the jump-target where fast | 5447 // If we generated fast-case code bind the jump-target where fast |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5715 // 2 (array): Arguments to the format string. | 5716 // 2 (array): Arguments to the format string. |
5716 ASSERT_EQ(args->length(), 3); | 5717 ASSERT_EQ(args->length(), 3); |
5717 #ifdef ENABLE_LOGGING_AND_PROFILING | 5718 #ifdef ENABLE_LOGGING_AND_PROFILING |
5718 if (ShouldGenerateLog(args->at(0))) { | 5719 if (ShouldGenerateLog(args->at(0))) { |
5719 Load(args->at(1)); | 5720 Load(args->at(1)); |
5720 Load(args->at(2)); | 5721 Load(args->at(2)); |
5721 frame_->CallRuntime(Runtime::kLog, 2); | 5722 frame_->CallRuntime(Runtime::kLog, 2); |
5722 } | 5723 } |
5723 #endif | 5724 #endif |
5724 // Finally, we're expected to leave a value on the top of the stack. | 5725 // Finally, we're expected to leave a value on the top of the stack. |
5725 frame_->Push(Factory::undefined_value()); | 5726 frame_->Push(FACTORY->undefined_value()); |
5726 } | 5727 } |
5727 | 5728 |
5728 | 5729 |
5729 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 5730 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
5730 ASSERT(args->length() == 1); | 5731 ASSERT(args->length() == 1); |
5731 Load(args->at(0)); | 5732 Load(args->at(0)); |
5732 Result value = frame_->Pop(); | 5733 Result value = frame_->Pop(); |
5733 value.ToRegister(); | 5734 value.ToRegister(); |
5734 ASSERT(value.is_valid()); | 5735 ASSERT(value.is_valid()); |
5735 Condition non_negative_smi = masm_->CheckNonNegativeSmi(value.reg()); | 5736 Condition non_negative_smi = masm_->CheckNonNegativeSmi(value.reg()); |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5978 void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { | 5979 void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { |
5979 // This generates a fast version of: | 5980 // This generates a fast version of: |
5980 // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') | 5981 // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') |
5981 ASSERT(args->length() == 1); | 5982 ASSERT(args->length() == 1); |
5982 Load(args->at(0)); | 5983 Load(args->at(0)); |
5983 Result obj = frame_->Pop(); | 5984 Result obj = frame_->Pop(); |
5984 obj.ToRegister(); | 5985 obj.ToRegister(); |
5985 Condition is_smi = masm_->CheckSmi(obj.reg()); | 5986 Condition is_smi = masm_->CheckSmi(obj.reg()); |
5986 destination()->false_target()->Branch(is_smi); | 5987 destination()->false_target()->Branch(is_smi); |
5987 | 5988 |
5988 __ Move(kScratchRegister, Factory::null_value()); | 5989 __ Move(kScratchRegister, FACTORY->null_value()); |
5989 __ cmpq(obj.reg(), kScratchRegister); | 5990 __ cmpq(obj.reg(), kScratchRegister); |
5990 destination()->true_target()->Branch(equal); | 5991 destination()->true_target()->Branch(equal); |
5991 | 5992 |
5992 __ movq(kScratchRegister, FieldOperand(obj.reg(), HeapObject::kMapOffset)); | 5993 __ movq(kScratchRegister, FieldOperand(obj.reg(), HeapObject::kMapOffset)); |
5993 // Undetectable objects behave like undefined when tested with typeof. | 5994 // Undetectable objects behave like undefined when tested with typeof. |
5994 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), | 5995 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), |
5995 Immediate(1 << Map::kIsUndetectable)); | 5996 Immediate(1 << Map::kIsUndetectable)); |
5996 destination()->false_target()->Branch(not_zero); | 5997 destination()->false_target()->Branch(not_zero); |
5997 __ movzxbq(kScratchRegister, | 5998 __ movzxbq(kScratchRegister, |
5998 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); | 5999 FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6070 // Calculate location of the first key name. | 6071 // Calculate location of the first key name. |
6071 __ addq(map_result_, | 6072 __ addq(map_result_, |
6072 Immediate(FixedArray::kHeaderSize + | 6073 Immediate(FixedArray::kHeaderSize + |
6073 DescriptorArray::kFirstIndex * kPointerSize)); | 6074 DescriptorArray::kFirstIndex * kPointerSize)); |
6074 // Loop through all the keys in the descriptor array. If one of these is the | 6075 // Loop through all the keys in the descriptor array. If one of these is the |
6075 // symbol valueOf the result is false. | 6076 // symbol valueOf the result is false. |
6076 Label entry, loop; | 6077 Label entry, loop; |
6077 __ jmp(&entry); | 6078 __ jmp(&entry); |
6078 __ bind(&loop); | 6079 __ bind(&loop); |
6079 __ movq(scratch2_, FieldOperand(map_result_, 0)); | 6080 __ movq(scratch2_, FieldOperand(map_result_, 0)); |
6080 __ Cmp(scratch2_, Factory::value_of_symbol()); | 6081 __ Cmp(scratch2_, FACTORY->value_of_symbol()); |
6081 __ j(equal, &false_result); | 6082 __ j(equal, &false_result); |
6082 __ addq(map_result_, Immediate(kPointerSize)); | 6083 __ addq(map_result_, Immediate(kPointerSize)); |
6083 __ bind(&entry); | 6084 __ bind(&entry); |
6084 __ cmpq(map_result_, scratch1_); | 6085 __ cmpq(map_result_, scratch1_); |
6085 __ j(not_equal, &loop); | 6086 __ j(not_equal, &loop); |
6086 | 6087 |
6087 // Reload map as register map_result_ was used as temporary above. | 6088 // Reload map as register map_result_ was used as temporary above. |
6088 __ movq(map_result_, FieldOperand(object_, HeapObject::kMapOffset)); | 6089 __ movq(map_result_, FieldOperand(object_, HeapObject::kMapOffset)); |
6089 | 6090 |
6090 // If a valueOf property is not found on the object check that it's | 6091 // If a valueOf property is not found on the object check that it's |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6282 __ movq(obj.reg(), | 6283 __ movq(obj.reg(), |
6283 FieldOperand(obj.reg(), JSFunction::kSharedFunctionInfoOffset)); | 6284 FieldOperand(obj.reg(), JSFunction::kSharedFunctionInfoOffset)); |
6284 __ movq(obj.reg(), | 6285 __ movq(obj.reg(), |
6285 FieldOperand(obj.reg(), | 6286 FieldOperand(obj.reg(), |
6286 SharedFunctionInfo::kInstanceClassNameOffset)); | 6287 SharedFunctionInfo::kInstanceClassNameOffset)); |
6287 frame_->Push(&obj); | 6288 frame_->Push(&obj); |
6288 leave.Jump(); | 6289 leave.Jump(); |
6289 | 6290 |
6290 // Functions have class 'Function'. | 6291 // Functions have class 'Function'. |
6291 function.Bind(); | 6292 function.Bind(); |
6292 frame_->Push(Factory::function_class_symbol()); | 6293 frame_->Push(FACTORY->function_class_symbol()); |
6293 leave.Jump(); | 6294 leave.Jump(); |
6294 | 6295 |
6295 // Objects with a non-function constructor have class 'Object'. | 6296 // Objects with a non-function constructor have class 'Object'. |
6296 non_function_constructor.Bind(); | 6297 non_function_constructor.Bind(); |
6297 frame_->Push(Factory::Object_symbol()); | 6298 frame_->Push(FACTORY->Object_symbol()); |
6298 leave.Jump(); | 6299 leave.Jump(); |
6299 | 6300 |
6300 // Non-JS objects have class null. | 6301 // Non-JS objects have class null. |
6301 null.Bind(); | 6302 null.Bind(); |
6302 frame_->Push(Factory::null_value()); | 6303 frame_->Push(FACTORY->null_value()); |
6303 | 6304 |
6304 // All done. | 6305 // All done. |
6305 leave.Bind(); | 6306 leave.Bind(); |
6306 } | 6307 } |
6307 | 6308 |
6308 | 6309 |
6309 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 6310 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
6310 ASSERT(args->length() == 1); | 6311 ASSERT(args->length() == 1); |
6311 JumpTarget leave; | 6312 JumpTarget leave; |
6312 Load(args->at(0)); // Load the object. | 6313 Load(args->at(0)); // Load the object. |
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6661 } | 6662 } |
6662 | 6663 |
6663 | 6664 |
6664 void CodeGenerator::GenerateGetFromCache(ZoneList<Expression*>* args) { | 6665 void CodeGenerator::GenerateGetFromCache(ZoneList<Expression*>* args) { |
6665 ASSERT_EQ(2, args->length()); | 6666 ASSERT_EQ(2, args->length()); |
6666 | 6667 |
6667 ASSERT_NE(NULL, args->at(0)->AsLiteral()); | 6668 ASSERT_NE(NULL, args->at(0)->AsLiteral()); |
6668 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); | 6669 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); |
6669 | 6670 |
6670 Handle<FixedArray> jsfunction_result_caches( | 6671 Handle<FixedArray> jsfunction_result_caches( |
6671 Top::global_context()->jsfunction_result_caches()); | 6672 Isolate::Current()->global_context()->jsfunction_result_caches()); |
6672 if (jsfunction_result_caches->length() <= cache_id) { | 6673 if (jsfunction_result_caches->length() <= cache_id) { |
6673 __ Abort("Attempt to use undefined cache."); | 6674 __ Abort("Attempt to use undefined cache."); |
6674 frame_->Push(Factory::undefined_value()); | 6675 frame_->Push(FACTORY->undefined_value()); |
6675 return; | 6676 return; |
6676 } | 6677 } |
6677 | 6678 |
6678 Load(args->at(1)); | 6679 Load(args->at(1)); |
6679 Result key = frame_->Pop(); | 6680 Result key = frame_->Pop(); |
6680 key.ToRegister(); | 6681 key.ToRegister(); |
6681 | 6682 |
6682 Result cache = allocator()->Allocate(); | 6683 Result cache = allocator()->Allocate(); |
6683 ASSERT(cache.is_valid()); | 6684 ASSERT(cache.is_valid()); |
6684 __ movq(cache.reg(), ContextOperand(rsi, Context::GLOBAL_INDEX)); | 6685 __ movq(cache.reg(), ContextOperand(rsi, Context::GLOBAL_INDEX)); |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6830 __ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done); | 6831 __ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done); |
6831 // Possible optimization: do a check that both values are smis | 6832 // Possible optimization: do a check that both values are smis |
6832 // (or them and test against Smi mask.) | 6833 // (or them and test against Smi mask.) |
6833 | 6834 |
6834 __ movq(tmp2.reg(), tmp1.reg()); | 6835 __ movq(tmp2.reg(), tmp1.reg()); |
6835 __ RecordWriteHelper(tmp1.reg(), index1.reg(), object.reg()); | 6836 __ RecordWriteHelper(tmp1.reg(), index1.reg(), object.reg()); |
6836 __ RecordWriteHelper(tmp2.reg(), index2.reg(), object.reg()); | 6837 __ RecordWriteHelper(tmp2.reg(), index2.reg(), object.reg()); |
6837 __ bind(&done); | 6838 __ bind(&done); |
6838 | 6839 |
6839 deferred->BindExit(); | 6840 deferred->BindExit(); |
6840 frame_->Push(Factory::undefined_value()); | 6841 frame_->Push(FACTORY->undefined_value()); |
6841 } | 6842 } |
6842 | 6843 |
6843 | 6844 |
6844 void CodeGenerator::GenerateCallFunction(ZoneList<Expression*>* args) { | 6845 void CodeGenerator::GenerateCallFunction(ZoneList<Expression*>* args) { |
6845 Comment cmnt(masm_, "[ GenerateCallFunction"); | 6846 Comment cmnt(masm_, "[ GenerateCallFunction"); |
6846 | 6847 |
6847 ASSERT(args->length() >= 2); | 6848 ASSERT(args->length() >= 2); |
6848 | 6849 |
6849 int n_args = args->length() - 2; // for receiver and function. | 6850 int n_args = args->length() - 2; // for receiver and function. |
6850 Load(args->at(0)); // receiver | 6851 Load(args->at(0)); // receiver |
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7174 Result number = allocator()->Allocate(); | 7175 Result number = allocator()->Allocate(); |
7175 ASSERT(number.is_valid()); | 7176 ASSERT(number.is_valid()); |
7176 __ movl(number.reg(), FieldOperand(string.reg(), String::kHashFieldOffset)); | 7177 __ movl(number.reg(), FieldOperand(string.reg(), String::kHashFieldOffset)); |
7177 __ IndexFromHash(number.reg(), number.reg()); | 7178 __ IndexFromHash(number.reg(), number.reg()); |
7178 string.Unuse(); | 7179 string.Unuse(); |
7179 frame_->Push(&number); | 7180 frame_->Push(&number); |
7180 } | 7181 } |
7181 | 7182 |
7182 | 7183 |
7183 void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) { | 7184 void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) { |
7184 frame_->Push(Factory::undefined_value()); | 7185 frame_->Push(FACTORY->undefined_value()); |
7185 } | 7186 } |
7186 | 7187 |
7187 | 7188 |
7188 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 7189 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
7189 if (CheckForInlineRuntimeCall(node)) { | 7190 if (CheckForInlineRuntimeCall(node)) { |
7190 return; | 7191 return; |
7191 } | 7192 } |
7192 | 7193 |
7193 ZoneList<Expression*>* args = node->arguments(); | 7194 ZoneList<Expression*>* args = node->arguments(); |
7194 Comment cmnt(masm_, "[ CallRuntime"); | 7195 Comment cmnt(masm_, "[ CallRuntime"); |
7195 Runtime::Function* function = node->function(); | 7196 const Runtime::Function* function = node->function(); |
7196 | 7197 |
7197 if (function == NULL) { | 7198 if (function == NULL) { |
7198 // Push the builtins object found in the current global object. | 7199 // Push the builtins object found in the current global object. |
7199 Result temp = allocator()->Allocate(); | 7200 Result temp = allocator()->Allocate(); |
7200 ASSERT(temp.is_valid()); | 7201 ASSERT(temp.is_valid()); |
7201 __ movq(temp.reg(), GlobalObjectOperand()); | 7202 __ movq(temp.reg(), GlobalObjectOperand()); |
7202 __ movq(temp.reg(), | 7203 __ movq(temp.reg(), |
7203 FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset)); | 7204 FieldOperand(temp.reg(), GlobalObject::kBuiltinsOffset)); |
7204 frame_->Push(&temp); | 7205 frame_->Push(&temp); |
7205 } | 7206 } |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7269 // variable. Sync the virtual frame eagerly so we can push the | 7270 // variable. Sync the virtual frame eagerly so we can push the |
7270 // arguments directly into place. | 7271 // arguments directly into place. |
7271 frame_->SyncRange(0, frame_->element_count() - 1); | 7272 frame_->SyncRange(0, frame_->element_count() - 1); |
7272 frame_->EmitPush(rsi); | 7273 frame_->EmitPush(rsi); |
7273 frame_->EmitPush(variable->name()); | 7274 frame_->EmitPush(variable->name()); |
7274 Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); | 7275 Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); |
7275 frame_->Push(&answer); | 7276 frame_->Push(&answer); |
7276 } else { | 7277 } else { |
7277 // Default: Result of deleting non-global, not dynamically | 7278 // Default: Result of deleting non-global, not dynamically |
7278 // introduced variables is false. | 7279 // introduced variables is false. |
7279 frame_->Push(Factory::false_value()); | 7280 frame_->Push(FACTORY->false_value()); |
7280 } | 7281 } |
7281 } else { | 7282 } else { |
7282 // Default: Result of deleting expressions is true. | 7283 // Default: Result of deleting expressions is true. |
7283 Load(node->expression()); // may have side-effects | 7284 Load(node->expression()); // may have side-effects |
7284 frame_->SetElementAt(0, Factory::true_value()); | 7285 frame_->SetElementAt(0, FACTORY->true_value()); |
7285 } | 7286 } |
7286 | 7287 |
7287 } else if (op == Token::TYPEOF) { | 7288 } else if (op == Token::TYPEOF) { |
7288 // Special case for loading the typeof expression; see comment on | 7289 // Special case for loading the typeof expression; see comment on |
7289 // LoadTypeofExpression(). | 7290 // LoadTypeofExpression(). |
7290 LoadTypeofExpression(node->expression()); | 7291 LoadTypeofExpression(node->expression()); |
7291 Result answer = frame_->CallRuntime(Runtime::kTypeof, 1); | 7292 Result answer = frame_->CallRuntime(Runtime::kTypeof, 1); |
7292 frame_->Push(&answer); | 7293 frame_->Push(&answer); |
7293 | 7294 |
7294 } else if (op == Token::VOID) { | 7295 } else if (op == Token::VOID) { |
7295 Expression* expression = node->expression(); | 7296 Expression* expression = node->expression(); |
7296 if (expression && expression->AsLiteral() && ( | 7297 if (expression && expression->AsLiteral() && ( |
7297 expression->AsLiteral()->IsTrue() || | 7298 expression->AsLiteral()->IsTrue() || |
7298 expression->AsLiteral()->IsFalse() || | 7299 expression->AsLiteral()->IsFalse() || |
7299 expression->AsLiteral()->handle()->IsNumber() || | 7300 expression->AsLiteral()->handle()->IsNumber() || |
7300 expression->AsLiteral()->handle()->IsString() || | 7301 expression->AsLiteral()->handle()->IsString() || |
7301 expression->AsLiteral()->handle()->IsJSRegExp() || | 7302 expression->AsLiteral()->handle()->IsJSRegExp() || |
7302 expression->AsLiteral()->IsNull())) { | 7303 expression->AsLiteral()->IsNull())) { |
7303 // Omit evaluating the value of the primitive literal. | 7304 // Omit evaluating the value of the primitive literal. |
7304 // It will be discarded anyway, and can have no side effect. | 7305 // It will be discarded anyway, and can have no side effect. |
7305 frame_->Push(Factory::undefined_value()); | 7306 frame_->Push(FACTORY->undefined_value()); |
7306 } else { | 7307 } else { |
7307 Load(node->expression()); | 7308 Load(node->expression()); |
7308 frame_->SetElementAt(0, Factory::undefined_value()); | 7309 frame_->SetElementAt(0, FACTORY->undefined_value()); |
7309 } | 7310 } |
7310 | 7311 |
7311 } else { | 7312 } else { |
7312 bool can_overwrite = node->expression()->ResultOverwriteAllowed(); | 7313 bool can_overwrite = node->expression()->ResultOverwriteAllowed(); |
7313 UnaryOverwriteMode overwrite = | 7314 UnaryOverwriteMode overwrite = |
7314 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; | 7315 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; |
7315 bool no_negative_zero = node->expression()->no_negative_zero(); | 7316 bool no_negative_zero = node->expression()->no_negative_zero(); |
7316 Load(node->expression()); | 7317 Load(node->expression()); |
7317 switch (op) { | 7318 switch (op) { |
7318 case Token::NOT: | 7319 case Token::NOT: |
(...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7770 (operation != NULL && operation->op() == Token::TYPEOF) && | 7771 (operation != NULL && operation->op() == Token::TYPEOF) && |
7771 (right->AsLiteral() != NULL && | 7772 (right->AsLiteral() != NULL && |
7772 right->AsLiteral()->handle()->IsString())) { | 7773 right->AsLiteral()->handle()->IsString())) { |
7773 Handle<String> check(Handle<String>::cast(right->AsLiteral()->handle())); | 7774 Handle<String> check(Handle<String>::cast(right->AsLiteral()->handle())); |
7774 | 7775 |
7775 // Load the operand and move it to a register. | 7776 // Load the operand and move it to a register. |
7776 LoadTypeofExpression(operation->expression()); | 7777 LoadTypeofExpression(operation->expression()); |
7777 Result answer = frame_->Pop(); | 7778 Result answer = frame_->Pop(); |
7778 answer.ToRegister(); | 7779 answer.ToRegister(); |
7779 | 7780 |
7780 if (check->Equals(Heap::number_symbol())) { | 7781 if (check->Equals(HEAP->number_symbol())) { |
7781 Condition is_smi = masm_->CheckSmi(answer.reg()); | 7782 Condition is_smi = masm_->CheckSmi(answer.reg()); |
7782 destination()->true_target()->Branch(is_smi); | 7783 destination()->true_target()->Branch(is_smi); |
7783 frame_->Spill(answer.reg()); | 7784 frame_->Spill(answer.reg()); |
7784 __ movq(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 7785 __ movq(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
7785 __ CompareRoot(answer.reg(), Heap::kHeapNumberMapRootIndex); | 7786 __ CompareRoot(answer.reg(), Heap::kHeapNumberMapRootIndex); |
7786 answer.Unuse(); | 7787 answer.Unuse(); |
7787 destination()->Split(equal); | 7788 destination()->Split(equal); |
7788 | 7789 |
7789 } else if (check->Equals(Heap::string_symbol())) { | 7790 } else if (check->Equals(HEAP->string_symbol())) { |
7790 Condition is_smi = masm_->CheckSmi(answer.reg()); | 7791 Condition is_smi = masm_->CheckSmi(answer.reg()); |
7791 destination()->false_target()->Branch(is_smi); | 7792 destination()->false_target()->Branch(is_smi); |
7792 | 7793 |
7793 // It can be an undetectable string object. | 7794 // It can be an undetectable string object. |
7794 __ movq(kScratchRegister, | 7795 __ movq(kScratchRegister, |
7795 FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 7796 FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
7796 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), | 7797 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), |
7797 Immediate(1 << Map::kIsUndetectable)); | 7798 Immediate(1 << Map::kIsUndetectable)); |
7798 destination()->false_target()->Branch(not_zero); | 7799 destination()->false_target()->Branch(not_zero); |
7799 __ CmpInstanceType(kScratchRegister, FIRST_NONSTRING_TYPE); | 7800 __ CmpInstanceType(kScratchRegister, FIRST_NONSTRING_TYPE); |
7800 answer.Unuse(); | 7801 answer.Unuse(); |
7801 destination()->Split(below); // Unsigned byte comparison needed. | 7802 destination()->Split(below); // Unsigned byte comparison needed. |
7802 | 7803 |
7803 } else if (check->Equals(Heap::boolean_symbol())) { | 7804 } else if (check->Equals(HEAP->boolean_symbol())) { |
7804 __ CompareRoot(answer.reg(), Heap::kTrueValueRootIndex); | 7805 __ CompareRoot(answer.reg(), Heap::kTrueValueRootIndex); |
7805 destination()->true_target()->Branch(equal); | 7806 destination()->true_target()->Branch(equal); |
7806 __ CompareRoot(answer.reg(), Heap::kFalseValueRootIndex); | 7807 __ CompareRoot(answer.reg(), Heap::kFalseValueRootIndex); |
7807 answer.Unuse(); | 7808 answer.Unuse(); |
7808 destination()->Split(equal); | 7809 destination()->Split(equal); |
7809 | 7810 |
7810 } else if (check->Equals(Heap::undefined_symbol())) { | 7811 } else if (check->Equals(HEAP->undefined_symbol())) { |
7811 __ CompareRoot(answer.reg(), Heap::kUndefinedValueRootIndex); | 7812 __ CompareRoot(answer.reg(), Heap::kUndefinedValueRootIndex); |
7812 destination()->true_target()->Branch(equal); | 7813 destination()->true_target()->Branch(equal); |
7813 | 7814 |
7814 Condition is_smi = masm_->CheckSmi(answer.reg()); | 7815 Condition is_smi = masm_->CheckSmi(answer.reg()); |
7815 destination()->false_target()->Branch(is_smi); | 7816 destination()->false_target()->Branch(is_smi); |
7816 | 7817 |
7817 // It can be an undetectable object. | 7818 // It can be an undetectable object. |
7818 __ movq(kScratchRegister, | 7819 __ movq(kScratchRegister, |
7819 FieldOperand(answer.reg(), HeapObject::kMapOffset)); | 7820 FieldOperand(answer.reg(), HeapObject::kMapOffset)); |
7820 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), | 7821 __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), |
7821 Immediate(1 << Map::kIsUndetectable)); | 7822 Immediate(1 << Map::kIsUndetectable)); |
7822 answer.Unuse(); | 7823 answer.Unuse(); |
7823 destination()->Split(not_zero); | 7824 destination()->Split(not_zero); |
7824 | 7825 |
7825 } else if (check->Equals(Heap::function_symbol())) { | 7826 } else if (check->Equals(HEAP->function_symbol())) { |
7826 Condition is_smi = masm_->CheckSmi(answer.reg()); | 7827 Condition is_smi = masm_->CheckSmi(answer.reg()); |
7827 destination()->false_target()->Branch(is_smi); | 7828 destination()->false_target()->Branch(is_smi); |
7828 frame_->Spill(answer.reg()); | 7829 frame_->Spill(answer.reg()); |
7829 __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg()); | 7830 __ CmpObjectType(answer.reg(), JS_FUNCTION_TYPE, answer.reg()); |
7830 destination()->true_target()->Branch(equal); | 7831 destination()->true_target()->Branch(equal); |
7831 // Regular expressions are callable so typeof == 'function'. | 7832 // Regular expressions are callable so typeof == 'function'. |
7832 __ CmpInstanceType(answer.reg(), JS_REGEXP_TYPE); | 7833 __ CmpInstanceType(answer.reg(), JS_REGEXP_TYPE); |
7833 answer.Unuse(); | 7834 answer.Unuse(); |
7834 destination()->Split(equal); | 7835 destination()->Split(equal); |
7835 | 7836 |
7836 } else if (check->Equals(Heap::object_symbol())) { | 7837 } else if (check->Equals(HEAP->object_symbol())) { |
7837 Condition is_smi = masm_->CheckSmi(answer.reg()); | 7838 Condition is_smi = masm_->CheckSmi(answer.reg()); |
7838 destination()->false_target()->Branch(is_smi); | 7839 destination()->false_target()->Branch(is_smi); |
7839 __ CompareRoot(answer.reg(), Heap::kNullValueRootIndex); | 7840 __ CompareRoot(answer.reg(), Heap::kNullValueRootIndex); |
7840 destination()->true_target()->Branch(equal); | 7841 destination()->true_target()->Branch(equal); |
7841 | 7842 |
7842 // Regular expressions are typeof == 'function', not 'object'. | 7843 // Regular expressions are typeof == 'function', not 'object'. |
7843 __ CmpObjectType(answer.reg(), JS_REGEXP_TYPE, kScratchRegister); | 7844 __ CmpObjectType(answer.reg(), JS_REGEXP_TYPE, kScratchRegister); |
7844 destination()->false_target()->Branch(equal); | 7845 destination()->false_target()->Branch(equal); |
7845 | 7846 |
7846 // It can be an undetectable object. | 7847 // It can be an undetectable object. |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7990 Register receiver_; | 7991 Register receiver_; |
7991 Handle<String> name_; | 7992 Handle<String> name_; |
7992 }; | 7993 }; |
7993 | 7994 |
7994 | 7995 |
7995 void DeferredReferenceGetNamedValue::Generate() { | 7996 void DeferredReferenceGetNamedValue::Generate() { |
7996 if (!receiver_.is(rax)) { | 7997 if (!receiver_.is(rax)) { |
7997 __ movq(rax, receiver_); | 7998 __ movq(rax, receiver_); |
7998 } | 7999 } |
7999 __ Move(rcx, name_); | 8000 __ Move(rcx, name_); |
8000 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 8001 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
| 8002 Builtins::LoadIC_Initialize)); |
8001 __ Call(ic, RelocInfo::CODE_TARGET); | 8003 __ Call(ic, RelocInfo::CODE_TARGET); |
8002 // The call must be followed by a test rax instruction to indicate | 8004 // The call must be followed by a test rax instruction to indicate |
8003 // that the inobject property case was inlined. | 8005 // that the inobject property case was inlined. |
8004 // | 8006 // |
8005 // Store the delta to the map check instruction here in the test | 8007 // Store the delta to the map check instruction here in the test |
8006 // instruction. Use masm_-> instead of the __ macro since the | 8008 // instruction. Use masm_-> instead of the __ macro since the |
8007 // latter can't return a value. | 8009 // latter can't return a value. |
8008 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 8010 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
8009 // Here we use masm_-> instead of the __ macro because this is the | 8011 // Here we use masm_-> instead of the __ macro because this is the |
8010 // instruction that gets patched and coverage code gets in the way. | 8012 // instruction that gets patched and coverage code gets in the way. |
8011 masm_->testl(rax, Immediate(-delta_to_patch_site)); | 8013 masm_->testl(rax, Immediate(-delta_to_patch_site)); |
8012 __ IncrementCounter(&Counters::named_load_inline_miss, 1); | 8014 __ IncrementCounter(COUNTERS->named_load_inline_miss(), 1); |
8013 | 8015 |
8014 if (!dst_.is(rax)) __ movq(dst_, rax); | 8016 if (!dst_.is(rax)) __ movq(dst_, rax); |
8015 } | 8017 } |
8016 | 8018 |
8017 | 8019 |
8018 class DeferredReferenceGetKeyedValue: public DeferredCode { | 8020 class DeferredReferenceGetKeyedValue: public DeferredCode { |
8019 public: | 8021 public: |
8020 explicit DeferredReferenceGetKeyedValue(Register dst, | 8022 explicit DeferredReferenceGetKeyedValue(Register dst, |
8021 Register receiver, | 8023 Register receiver, |
8022 Register key) | 8024 Register key) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8055 } else { | 8057 } else { |
8056 __ movq(rax, key_); | 8058 __ movq(rax, key_); |
8057 __ movq(rdx, receiver_); | 8059 __ movq(rdx, receiver_); |
8058 } | 8060 } |
8059 // Calculate the delta from the IC call instruction to the map check | 8061 // Calculate the delta from the IC call instruction to the map check |
8060 // movq instruction in the inlined version. This delta is stored in | 8062 // movq instruction in the inlined version. This delta is stored in |
8061 // a test(rax, delta) instruction after the call so that we can find | 8063 // a test(rax, delta) instruction after the call so that we can find |
8062 // it in the IC initialization code and patch the movq instruction. | 8064 // it in the IC initialization code and patch the movq instruction. |
8063 // This means that we cannot allow test instructions after calls to | 8065 // This means that we cannot allow test instructions after calls to |
8064 // KeyedLoadIC stubs in other places. | 8066 // KeyedLoadIC stubs in other places. |
8065 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 8067 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
| 8068 Builtins::KeyedLoadIC_Initialize)); |
8066 __ Call(ic, RelocInfo::CODE_TARGET); | 8069 __ Call(ic, RelocInfo::CODE_TARGET); |
8067 // The delta from the start of the map-compare instruction to the | 8070 // The delta from the start of the map-compare instruction to the |
8068 // test instruction. We use masm_-> directly here instead of the __ | 8071 // test instruction. We use masm_-> directly here instead of the __ |
8069 // macro because the macro sometimes uses macro expansion to turn | 8072 // macro because the macro sometimes uses macro expansion to turn |
8070 // into something that can't return a value. This is encountered | 8073 // into something that can't return a value. This is encountered |
8071 // when doing generated code coverage tests. | 8074 // when doing generated code coverage tests. |
8072 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 8075 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
8073 // Here we use masm_-> instead of the __ macro because this is the | 8076 // Here we use masm_-> instead of the __ macro because this is the |
8074 // instruction that gets patched and coverage code gets in the way. | 8077 // instruction that gets patched and coverage code gets in the way. |
8075 // TODO(X64): Consider whether it's worth switching the test to a | 8078 // TODO(X64): Consider whether it's worth switching the test to a |
8076 // 7-byte NOP with non-zero immediate (0f 1f 80 xxxxxxxx) which won't | 8079 // 7-byte NOP with non-zero immediate (0f 1f 80 xxxxxxxx) which won't |
8077 // be generated normally. | 8080 // be generated normally. |
8078 masm_->testl(rax, Immediate(-delta_to_patch_site)); | 8081 masm_->testl(rax, Immediate(-delta_to_patch_site)); |
8079 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); | 8082 __ IncrementCounter(COUNTERS->keyed_load_inline_miss(), 1); |
8080 | 8083 |
8081 if (!dst_.is(rax)) __ movq(dst_, rax); | 8084 if (!dst_.is(rax)) __ movq(dst_, rax); |
8082 } | 8085 } |
8083 | 8086 |
8084 | 8087 |
8085 class DeferredReferenceSetKeyedValue: public DeferredCode { | 8088 class DeferredReferenceSetKeyedValue: public DeferredCode { |
8086 public: | 8089 public: |
8087 DeferredReferenceSetKeyedValue(Register value, | 8090 DeferredReferenceSetKeyedValue(Register value, |
8088 Register key, | 8091 Register key, |
8089 Register receiver, | 8092 Register receiver, |
(...skipping 12 matching lines...) Expand all Loading... |
8102 private: | 8105 private: |
8103 Register value_; | 8106 Register value_; |
8104 Register key_; | 8107 Register key_; |
8105 Register receiver_; | 8108 Register receiver_; |
8106 Label patch_site_; | 8109 Label patch_site_; |
8107 StrictModeFlag strict_mode_; | 8110 StrictModeFlag strict_mode_; |
8108 }; | 8111 }; |
8109 | 8112 |
8110 | 8113 |
8111 void DeferredReferenceSetKeyedValue::Generate() { | 8114 void DeferredReferenceSetKeyedValue::Generate() { |
8112 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); | 8115 __ IncrementCounter(COUNTERS->keyed_store_inline_miss(), 1); |
8113 // Move value, receiver, and key to registers rax, rdx, and rcx, as | 8116 // Move value, receiver, and key to registers rax, rdx, and rcx, as |
8114 // the IC stub expects. | 8117 // the IC stub expects. |
8115 // Move value to rax, using xchg if the receiver or key is in rax. | 8118 // Move value to rax, using xchg if the receiver or key is in rax. |
8116 if (!value_.is(rax)) { | 8119 if (!value_.is(rax)) { |
8117 if (!receiver_.is(rax) && !key_.is(rax)) { | 8120 if (!receiver_.is(rax) && !key_.is(rax)) { |
8118 __ movq(rax, value_); | 8121 __ movq(rax, value_); |
8119 } else { | 8122 } else { |
8120 __ xchg(rax, value_); | 8123 __ xchg(rax, value_); |
8121 // Update receiver_ and key_ if they are affected by the swap. | 8124 // Update receiver_ and key_ if they are affected by the swap. |
8122 if (receiver_.is(rax)) { | 8125 if (receiver_.is(rax)) { |
(...skipping 26 matching lines...) Expand all Loading... |
8149 __ movq(rcx, key_); | 8152 __ movq(rcx, key_); |
8150 } | 8153 } |
8151 } else if (key_.is(rcx)) { | 8154 } else if (key_.is(rcx)) { |
8152 __ movq(rdx, receiver_); | 8155 __ movq(rdx, receiver_); |
8153 } else { | 8156 } else { |
8154 __ movq(rcx, key_); | 8157 __ movq(rcx, key_); |
8155 __ movq(rdx, receiver_); | 8158 __ movq(rdx, receiver_); |
8156 } | 8159 } |
8157 | 8160 |
8158 // Call the IC stub. | 8161 // Call the IC stub. |
8159 Handle<Code> ic(Builtins::builtin( | 8162 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
8160 (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict | 8163 (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict |
8161 : Builtins::KeyedStoreIC_Initialize)); | 8164 : Builtins::KeyedStoreIC_Initialize)); |
8162 __ Call(ic, RelocInfo::CODE_TARGET); | 8165 __ Call(ic, RelocInfo::CODE_TARGET); |
8163 // The delta from the start of the map-compare instructions (initial movq) | 8166 // The delta from the start of the map-compare instructions (initial movq) |
8164 // to the test instruction. We use masm_-> directly here instead of the | 8167 // to the test instruction. We use masm_-> directly here instead of the |
8165 // __ macro because the macro sometimes uses macro expansion to turn | 8168 // __ macro because the macro sometimes uses macro expansion to turn |
8166 // into something that can't return a value. This is encountered | 8169 // into something that can't return a value. This is encountered |
8167 // when doing generated code coverage tests. | 8170 // when doing generated code coverage tests. |
8168 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); | 8171 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); |
8169 // Here we use masm_-> instead of the __ macro because this is the | 8172 // Here we use masm_-> instead of the __ macro because this is the |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8218 DeferredReferenceGetNamedValue* deferred = | 8221 DeferredReferenceGetNamedValue* deferred = |
8219 new DeferredReferenceGetNamedValue(result.reg(), receiver.reg(), name); | 8222 new DeferredReferenceGetNamedValue(result.reg(), receiver.reg(), name); |
8220 | 8223 |
8221 // Check that the receiver is a heap object. | 8224 // Check that the receiver is a heap object. |
8222 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); | 8225 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); |
8223 | 8226 |
8224 __ bind(deferred->patch_site()); | 8227 __ bind(deferred->patch_site()); |
8225 // This is the map check instruction that will be patched (so we can't | 8228 // This is the map check instruction that will be patched (so we can't |
8226 // use the double underscore macro that may insert instructions). | 8229 // use the double underscore macro that may insert instructions). |
8227 // Initially use an invalid map to force a failure. | 8230 // Initially use an invalid map to force a failure. |
8228 masm()->movq(kScratchRegister, Factory::null_value(), | 8231 masm()->movq(kScratchRegister, FACTORY->null_value(), |
8229 RelocInfo::EMBEDDED_OBJECT); | 8232 RelocInfo::EMBEDDED_OBJECT); |
8230 masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | 8233 masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
8231 kScratchRegister); | 8234 kScratchRegister); |
8232 // This branch is always a forwards branch so it's always a fixed | 8235 // This branch is always a forwards branch so it's always a fixed |
8233 // size which allows the assert below to succeed and patching to work. | 8236 // size which allows the assert below to succeed and patching to work. |
8234 // Don't use deferred->Branch(...), since that might add coverage code. | 8237 // Don't use deferred->Branch(...), since that might add coverage code. |
8235 masm()->j(not_equal, deferred->entry_label()); | 8238 masm()->j(not_equal, deferred->entry_label()); |
8236 | 8239 |
8237 // The delta from the patch label to the load offset must be | 8240 // The delta from the patch label to the load offset must be |
8238 // statically known. | 8241 // statically known. |
8239 ASSERT(masm()->SizeOfCodeGeneratedSince(deferred->patch_site()) == | 8242 ASSERT(masm()->SizeOfCodeGeneratedSince(deferred->patch_site()) == |
8240 LoadIC::kOffsetToLoadInstruction); | 8243 LoadIC::kOffsetToLoadInstruction); |
8241 // The initial (invalid) offset has to be large enough to force | 8244 // The initial (invalid) offset has to be large enough to force |
8242 // a 32-bit instruction encoding to allow patching with an | 8245 // a 32-bit instruction encoding to allow patching with an |
8243 // arbitrary offset. Use kMaxInt (minus kHeapObjectTag). | 8246 // arbitrary offset. Use kMaxInt (minus kHeapObjectTag). |
8244 int offset = kMaxInt; | 8247 int offset = kMaxInt; |
8245 masm()->movq(result.reg(), FieldOperand(receiver.reg(), offset)); | 8248 masm()->movq(result.reg(), FieldOperand(receiver.reg(), offset)); |
8246 | 8249 |
8247 __ IncrementCounter(&Counters::named_load_inline, 1); | 8250 __ IncrementCounter(COUNTERS->named_load_inline(), 1); |
8248 deferred->BindExit(); | 8251 deferred->BindExit(); |
8249 } | 8252 } |
8250 ASSERT(frame()->height() == original_height - 1); | 8253 ASSERT(frame()->height() == original_height - 1); |
8251 return result; | 8254 return result; |
8252 } | 8255 } |
8253 | 8256 |
8254 | 8257 |
8255 Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) { | 8258 Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) { |
8256 #ifdef DEBUG | 8259 #ifdef DEBUG |
8257 int expected_height = frame()->height() - (is_contextual ? 1 : 2); | 8260 int expected_height = frame()->height() - (is_contextual ? 1 : 2); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8295 Condition is_smi = masm()->CheckSmi(receiver.reg()); | 8298 Condition is_smi = masm()->CheckSmi(receiver.reg()); |
8296 slow.Branch(is_smi, &value, &receiver); | 8299 slow.Branch(is_smi, &value, &receiver); |
8297 | 8300 |
8298 // This is the map check instruction that will be patched. | 8301 // This is the map check instruction that will be patched. |
8299 // Initially use an invalid map to force a failure. The exact | 8302 // Initially use an invalid map to force a failure. The exact |
8300 // instruction sequence is important because we use the | 8303 // instruction sequence is important because we use the |
8301 // kOffsetToStoreInstruction constant for patching. We avoid using | 8304 // kOffsetToStoreInstruction constant for patching. We avoid using |
8302 // the __ macro for the following two instructions because it | 8305 // the __ macro for the following two instructions because it |
8303 // might introduce extra instructions. | 8306 // might introduce extra instructions. |
8304 __ bind(&patch_site); | 8307 __ bind(&patch_site); |
8305 masm()->movq(kScratchRegister, Factory::null_value(), | 8308 masm()->movq(kScratchRegister, FACTORY->null_value(), |
8306 RelocInfo::EMBEDDED_OBJECT); | 8309 RelocInfo::EMBEDDED_OBJECT); |
8307 masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | 8310 masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
8308 kScratchRegister); | 8311 kScratchRegister); |
8309 // This branch is always a forwards branch so it's always a fixed size | 8312 // This branch is always a forwards branch so it's always a fixed size |
8310 // which allows the assert below to succeed and patching to work. | 8313 // which allows the assert below to succeed and patching to work. |
8311 slow.Branch(not_equal, &value, &receiver); | 8314 slow.Branch(not_equal, &value, &receiver); |
8312 | 8315 |
8313 // The delta from the patch label to the store offset must be | 8316 // The delta from the patch label to the store offset must be |
8314 // statically known. | 8317 // statically known. |
8315 ASSERT(masm()->SizeOfCodeGeneratedSince(&patch_site) == | 8318 ASSERT(masm()->SizeOfCodeGeneratedSince(&patch_site) == |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8409 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); | 8412 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); |
8410 | 8413 |
8411 // Check that the receiver has the expected map. | 8414 // Check that the receiver has the expected map. |
8412 // Initially, use an invalid map. The map is patched in the IC | 8415 // Initially, use an invalid map. The map is patched in the IC |
8413 // initialization code. | 8416 // initialization code. |
8414 __ bind(deferred->patch_site()); | 8417 __ bind(deferred->patch_site()); |
8415 // Use masm-> here instead of the double underscore macro since extra | 8418 // Use masm-> here instead of the double underscore macro since extra |
8416 // coverage code can interfere with the patching. Do not use a load | 8419 // coverage code can interfere with the patching. Do not use a load |
8417 // from the root array to load null_value, since the load must be patched | 8420 // from the root array to load null_value, since the load must be patched |
8418 // with the expected receiver map, which is not in the root array. | 8421 // with the expected receiver map, which is not in the root array. |
8419 masm_->movq(kScratchRegister, Factory::null_value(), | 8422 masm_->movq(kScratchRegister, FACTORY->null_value(), |
8420 RelocInfo::EMBEDDED_OBJECT); | 8423 RelocInfo::EMBEDDED_OBJECT); |
8421 masm_->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), | 8424 masm_->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), |
8422 kScratchRegister); | 8425 kScratchRegister); |
8423 deferred->Branch(not_equal); | 8426 deferred->Branch(not_equal); |
8424 | 8427 |
8425 __ JumpUnlessNonNegativeSmi(key.reg(), deferred->entry_label()); | 8428 __ JumpUnlessNonNegativeSmi(key.reg(), deferred->entry_label()); |
8426 | 8429 |
8427 // Get the elements array from the receiver. | 8430 // Get the elements array from the receiver. |
8428 __ movq(elements.reg(), | 8431 __ movq(elements.reg(), |
8429 FieldOperand(receiver.reg(), JSObject::kElementsOffset)); | 8432 FieldOperand(receiver.reg(), JSObject::kElementsOffset)); |
(...skipping 14 matching lines...) Expand all Loading... |
8444 SmiIndex index = | 8447 SmiIndex index = |
8445 masm_->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); | 8448 masm_->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); |
8446 __ movq(elements.reg(), | 8449 __ movq(elements.reg(), |
8447 FieldOperand(elements.reg(), | 8450 FieldOperand(elements.reg(), |
8448 index.reg, | 8451 index.reg, |
8449 index.scale, | 8452 index.scale, |
8450 FixedArray::kHeaderSize)); | 8453 FixedArray::kHeaderSize)); |
8451 result = elements; | 8454 result = elements; |
8452 __ CompareRoot(result.reg(), Heap::kTheHoleValueRootIndex); | 8455 __ CompareRoot(result.reg(), Heap::kTheHoleValueRootIndex); |
8453 deferred->Branch(equal); | 8456 deferred->Branch(equal); |
8454 __ IncrementCounter(&Counters::keyed_load_inline, 1); | 8457 __ IncrementCounter(COUNTERS->keyed_load_inline(), 1); |
8455 | 8458 |
8456 deferred->BindExit(); | 8459 deferred->BindExit(); |
8457 } else { | 8460 } else { |
8458 Comment cmnt(masm_, "[ Load from keyed Property"); | 8461 Comment cmnt(masm_, "[ Load from keyed Property"); |
8459 result = frame_->CallKeyedLoadIC(RelocInfo::CODE_TARGET); | 8462 result = frame_->CallKeyedLoadIC(RelocInfo::CODE_TARGET); |
8460 // Make sure that we do not have a test instruction after the | 8463 // Make sure that we do not have a test instruction after the |
8461 // call. A test instruction after the call is used to | 8464 // call. A test instruction after the call is used to |
8462 // indicate that we have generated an inline version of the | 8465 // indicate that we have generated an inline version of the |
8463 // keyed load. The explicit nop instruction is here because | 8466 // keyed load. The explicit nop instruction is here because |
8464 // the push that follows might be peep-hole optimized away. | 8467 // the push that follows might be peep-hole optimized away. |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8533 } | 8536 } |
8534 | 8537 |
8535 __ bind(&in_new_space); | 8538 __ bind(&in_new_space); |
8536 // Bind the deferred code patch site to be able to locate the fixed | 8539 // Bind the deferred code patch site to be able to locate the fixed |
8537 // array map comparison. When debugging, we patch this comparison to | 8540 // array map comparison. When debugging, we patch this comparison to |
8538 // always fail so that we will hit the IC call in the deferred code | 8541 // always fail so that we will hit the IC call in the deferred code |
8539 // which will allow the debugger to break for fast case stores. | 8542 // which will allow the debugger to break for fast case stores. |
8540 __ bind(deferred->patch_site()); | 8543 __ bind(deferred->patch_site()); |
8541 // Avoid using __ to ensure the distance from patch_site | 8544 // Avoid using __ to ensure the distance from patch_site |
8542 // to the map address is always the same. | 8545 // to the map address is always the same. |
8543 masm()->movq(kScratchRegister, Factory::fixed_array_map(), | 8546 masm()->movq(kScratchRegister, FACTORY->fixed_array_map(), |
8544 RelocInfo::EMBEDDED_OBJECT); | 8547 RelocInfo::EMBEDDED_OBJECT); |
8545 __ cmpq(FieldOperand(tmp.reg(), HeapObject::kMapOffset), | 8548 __ cmpq(FieldOperand(tmp.reg(), HeapObject::kMapOffset), |
8546 kScratchRegister); | 8549 kScratchRegister); |
8547 deferred->Branch(not_equal); | 8550 deferred->Branch(not_equal); |
8548 | 8551 |
8549 // Check that the key is within bounds. Both the key and the length of | 8552 // Check that the key is within bounds. Both the key and the length of |
8550 // the JSArray are smis (because the fixed array check above ensures the | 8553 // the JSArray are smis (because the fixed array check above ensures the |
8551 // elements are in fast case). Use unsigned comparison to handle negative | 8554 // elements are in fast case). Use unsigned comparison to handle negative |
8552 // keys. | 8555 // keys. |
8553 __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset), | 8556 __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset), |
8554 key.reg()); | 8557 key.reg()); |
8555 deferred->Branch(below_equal); | 8558 deferred->Branch(below_equal); |
8556 | 8559 |
8557 // Store the value. | 8560 // Store the value. |
8558 SmiIndex index = | 8561 SmiIndex index = |
8559 masm()->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); | 8562 masm()->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); |
8560 __ movq(FieldOperand(tmp.reg(), | 8563 __ movq(FieldOperand(tmp.reg(), |
8561 index.reg, | 8564 index.reg, |
8562 index.scale, | 8565 index.scale, |
8563 FixedArray::kHeaderSize), | 8566 FixedArray::kHeaderSize), |
8564 result.reg()); | 8567 result.reg()); |
8565 __ IncrementCounter(&Counters::keyed_store_inline, 1); | 8568 __ IncrementCounter(COUNTERS->keyed_store_inline(), 1); |
8566 | 8569 |
8567 deferred->BindExit(); | 8570 deferred->BindExit(); |
8568 } else { | 8571 } else { |
8569 result = frame()->CallKeyedStoreIC(strict_mode_flag()); | 8572 result = frame()->CallKeyedStoreIC(strict_mode_flag()); |
8570 // Make sure that we do not have a test instruction after the | 8573 // Make sure that we do not have a test instruction after the |
8571 // call. A test instruction after the call is used to | 8574 // call. A test instruction after the call is used to |
8572 // indicate that we have generated an inline version of the | 8575 // indicate that we have generated an inline version of the |
8573 // keyed store. | 8576 // keyed store. |
8574 __ nop(); | 8577 __ nop(); |
8575 } | 8578 } |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8838 } | 8841 } |
8839 | 8842 |
8840 #endif | 8843 #endif |
8841 | 8844 |
8842 | 8845 |
8843 #undef __ | 8846 #undef __ |
8844 | 8847 |
8845 } } // namespace v8::internal | 8848 } } // namespace v8::internal |
8846 | 8849 |
8847 #endif // V8_TARGET_ARCH_X64 | 8850 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |