Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(100)

Side by Side Diff: src/x64/stub-cache-x64.cc

Issue 6597029: [Isolates] Merge r 6300:6500 from bleeding_edge to isolates. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/isolates/
Patch Set: Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/macro-assembler-x64.cc ('k') | test/cctest/cctest.status » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 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 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 ASSERT(kNotStringTag != 0); 303 ASSERT(kNotStringTag != 0);
304 __ testl(scratch, Immediate(kNotStringTag)); 304 __ testl(scratch, Immediate(kNotStringTag));
305 __ j(not_zero, non_string_object); 305 __ j(not_zero, non_string_object);
306 } 306 }
307 307
308 308
309 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, 309 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
310 Register receiver, 310 Register receiver,
311 Register scratch1, 311 Register scratch1,
312 Register scratch2, 312 Register scratch2,
313 Label* miss) { 313 Label* miss,
314 bool support_wrappers) {
314 Label check_wrapper; 315 Label check_wrapper;
315 316
316 // Check if the object is a string leaving the instance type in the 317 // Check if the object is a string leaving the instance type in the
317 // scratch register. 318 // scratch register.
318 GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper); 319 GenerateStringCheck(masm, receiver, scratch1, miss,
320 support_wrappers ? &check_wrapper : miss);
319 321
320 // Load length directly from the string. 322 // Load length directly from the string.
321 __ movq(rax, FieldOperand(receiver, String::kLengthOffset)); 323 __ movq(rax, FieldOperand(receiver, String::kLengthOffset));
322 __ ret(0); 324 __ ret(0);
323 325
324 // Check if the object is a JSValue wrapper. 326 if (support_wrappers) {
325 __ bind(&check_wrapper); 327 // Check if the object is a JSValue wrapper.
326 __ cmpl(scratch1, Immediate(JS_VALUE_TYPE)); 328 __ bind(&check_wrapper);
327 __ j(not_equal, miss); 329 __ cmpl(scratch1, Immediate(JS_VALUE_TYPE));
330 __ j(not_equal, miss);
328 331
329 // Check if the wrapped value is a string and load the length 332 // Check if the wrapped value is a string and load the length
330 // directly if it is. 333 // directly if it is.
331 __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); 334 __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
332 GenerateStringCheck(masm, scratch2, scratch1, miss, miss); 335 GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
333 __ movq(rax, FieldOperand(scratch2, String::kLengthOffset)); 336 __ movq(rax, FieldOperand(scratch2, String::kLengthOffset));
334 __ ret(0); 337 __ ret(0);
338 }
335 } 339 }
336 340
337 341
338 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, 342 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
339 Register receiver, 343 Register receiver,
340 Register result, 344 Register result,
341 Register scratch, 345 Register scratch,
342 Label* miss_label) { 346 Label* miss_label) {
343 __ TryGetFunctionPrototype(receiver, result, miss_label); 347 __ TryGetFunctionPrototype(receiver, result, miss_label);
344 if (!result.is(rax)) __ movq(rax, result); 348 if (!result.is(rax)) __ movq(rax, result);
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
433 // -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal 437 // -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal
434 // frame. 438 // frame.
435 // ----------------------------------- 439 // -----------------------------------
436 __ movq(scratch, Operand(rsp, 0)); 440 __ movq(scratch, Operand(rsp, 0));
437 __ movq(Operand(rsp, kFastApiCallArguments * kPointerSize), scratch); 441 __ movq(Operand(rsp, kFastApiCallArguments * kPointerSize), scratch);
438 __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments)); 442 __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments));
439 } 443 }
440 444
441 445
442 // Generates call to API function. 446 // Generates call to API function.
443 static bool GenerateFastApiCall(MacroAssembler* masm, 447 static MaybeObject* GenerateFastApiCall(MacroAssembler* masm,
444 const CallOptimization& optimization, 448 const CallOptimization& optimization,
445 int argc, 449 int argc) {
446 Failure** failure) {
447 // ----------- S t a t e ------------- 450 // ----------- S t a t e -------------
448 // -- rsp[0] : return address 451 // -- rsp[0] : return address
449 // -- rsp[8] : object passing the type check 452 // -- rsp[8] : object passing the type check
450 // (last fast api call extra argument, 453 // (last fast api call extra argument,
451 // set by CheckPrototypes) 454 // set by CheckPrototypes)
452 // -- rsp[16] : api function 455 // -- rsp[16] : api function
453 // (first fast api call extra argument) 456 // (first fast api call extra argument)
454 // -- rsp[24] : api call data 457 // -- rsp[24] : api call data
455 // -- rsp[32] : last argument 458 // -- rsp[32] : last argument
456 // -- ... 459 // -- ...
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
500 __ Set(StackSpaceOperand(2), argc); // v8::Arguments::length_. 503 __ Set(StackSpaceOperand(2), argc); // v8::Arguments::length_.
501 // v8::Arguments::is_construct_call_. 504 // v8::Arguments::is_construct_call_.
502 __ Set(StackSpaceOperand(3), 0); 505 __ Set(StackSpaceOperand(3), 0);
503 506
504 // v8::InvocationCallback's argument. 507 // v8::InvocationCallback's argument.
505 __ lea(arguments_arg, StackSpaceOperand(0)); 508 __ lea(arguments_arg, StackSpaceOperand(0));
506 // Emitting a stub call may try to allocate (if the code is not 509 // Emitting a stub call may try to allocate (if the code is not
507 // already generated). Do not allow the assembler to perform a 510 // already generated). Do not allow the assembler to perform a
508 // garbage collection but instead return the allocation failure 511 // garbage collection but instead return the allocation failure
509 // object. 512 // object.
510 MaybeObject* result = 513 return masm->TryCallApiFunctionAndReturn(&fun,
511 masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1); 514 argc + kFastApiCallArguments + 1);
512 if (result->IsFailure()) {
513 *failure = Failure::cast(result);
514 return false;
515 }
516 return true;
517 } 515 }
518 516
519 517
520 class CallInterceptorCompiler BASE_EMBEDDED { 518 class CallInterceptorCompiler BASE_EMBEDDED {
521 public: 519 public:
522 CallInterceptorCompiler(StubCompiler* stub_compiler, 520 CallInterceptorCompiler(StubCompiler* stub_compiler,
523 const ParameterCount& arguments, 521 const ParameterCount& arguments,
524 Register name) 522 Register name)
525 : stub_compiler_(stub_compiler), 523 : stub_compiler_(stub_compiler),
526 arguments_(arguments), 524 arguments_(arguments),
527 name_(name) {} 525 name_(name) {}
528 526
529 bool Compile(MacroAssembler* masm, 527 MaybeObject* Compile(MacroAssembler* masm,
530 JSObject* object, 528 JSObject* object,
531 JSObject* holder, 529 JSObject* holder,
532 String* name, 530 String* name,
533 LookupResult* lookup, 531 LookupResult* lookup,
534 Register receiver, 532 Register receiver,
535 Register scratch1, 533 Register scratch1,
536 Register scratch2, 534 Register scratch2,
537 Register scratch3, 535 Register scratch3,
538 Label* miss, 536 Label* miss) {
539 Failure** failure) {
540 ASSERT(holder->HasNamedInterceptor()); 537 ASSERT(holder->HasNamedInterceptor());
541 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); 538 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
542 539
543 // Check that the receiver isn't a smi. 540 // Check that the receiver isn't a smi.
544 __ JumpIfSmi(receiver, miss); 541 __ JumpIfSmi(receiver, miss);
545 542
546 CallOptimization optimization(lookup); 543 CallOptimization optimization(lookup);
547 544
548 if (optimization.is_constant_call()) { 545 if (optimization.is_constant_call()) {
549 return CompileCacheable(masm, 546 return CompileCacheable(masm,
550 object, 547 object,
551 receiver, 548 receiver,
552 scratch1, 549 scratch1,
553 scratch2, 550 scratch2,
554 scratch3, 551 scratch3,
555 holder, 552 holder,
556 lookup, 553 lookup,
557 name, 554 name,
558 optimization, 555 optimization,
559 miss, 556 miss);
560 failure);
561 } else { 557 } else {
562 CompileRegular(masm, 558 CompileRegular(masm,
563 object, 559 object,
564 receiver, 560 receiver,
565 scratch1, 561 scratch1,
566 scratch2, 562 scratch2,
567 scratch3, 563 scratch3,
568 name, 564 name,
569 holder, 565 holder,
570 miss); 566 miss);
571 return true; 567 return HEAP->undefined_value(); // Success.
572 } 568 }
573 } 569 }
574 570
575 private: 571 private:
576 bool CompileCacheable(MacroAssembler* masm, 572 MaybeObject* CompileCacheable(MacroAssembler* masm,
577 JSObject* object, 573 JSObject* object,
578 Register receiver, 574 Register receiver,
579 Register scratch1, 575 Register scratch1,
580 Register scratch2, 576 Register scratch2,
581 Register scratch3, 577 Register scratch3,
582 JSObject* interceptor_holder, 578 JSObject* interceptor_holder,
583 LookupResult* lookup, 579 LookupResult* lookup,
584 String* name, 580 String* name,
585 const CallOptimization& optimization, 581 const CallOptimization& optimization,
586 Label* miss_label, 582 Label* miss_label) {
587 Failure** failure) {
588 ASSERT(optimization.is_constant_call()); 583 ASSERT(optimization.is_constant_call());
589 ASSERT(!lookup->holder()->IsGlobalObject()); 584 ASSERT(!lookup->holder()->IsGlobalObject());
590 585
591 int depth1 = kInvalidProtoDepth; 586 int depth1 = kInvalidProtoDepth;
592 int depth2 = kInvalidProtoDepth; 587 int depth2 = kInvalidProtoDepth;
593 bool can_do_fast_api_call = false; 588 bool can_do_fast_api_call = false;
594 if (optimization.is_simple_api_call() && 589 if (optimization.is_simple_api_call() &&
595 !lookup->holder()->IsGlobalObject()) { 590 !lookup->holder()->IsGlobalObject()) {
596 depth1 = 591 depth1 =
597 optimization.GetPrototypeDepthOfExpectedType(object, 592 optimization.GetPrototypeDepthOfExpectedType(object,
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
639 } else { 634 } else {
640 // CheckPrototypes has a side effect of fetching a 'holder' 635 // CheckPrototypes has a side effect of fetching a 'holder'
641 // for API (object which is instanceof for the signature). It's 636 // for API (object which is instanceof for the signature). It's
642 // safe to omit it here, as if present, it should be fetched 637 // safe to omit it here, as if present, it should be fetched
643 // by the previous CheckPrototypes. 638 // by the previous CheckPrototypes.
644 ASSERT(depth2 == kInvalidProtoDepth); 639 ASSERT(depth2 == kInvalidProtoDepth);
645 } 640 }
646 641
647 // Invoke function. 642 // Invoke function.
648 if (can_do_fast_api_call) { 643 if (can_do_fast_api_call) {
649 bool success = GenerateFastApiCall(masm, 644 MaybeObject* result = GenerateFastApiCall(masm,
650 optimization, 645 optimization,
651 arguments_.immediate(), 646 arguments_.immediate());
652 failure); 647 if (result->IsFailure()) return result;
653 if (!success) {
654 return false;
655 }
656 } else { 648 } else {
657 __ InvokeFunction(optimization.constant_function(), arguments_, 649 __ InvokeFunction(optimization.constant_function(), arguments_,
658 JUMP_FUNCTION); 650 JUMP_FUNCTION);
659 } 651 }
660 652
661 // Deferred code for fast API call case---clean preallocated space. 653 // Deferred code for fast API call case---clean preallocated space.
662 if (can_do_fast_api_call) { 654 if (can_do_fast_api_call) {
663 __ bind(&miss_cleanup); 655 __ bind(&miss_cleanup);
664 FreeSpaceForFastApiCall(masm, scratch1); 656 FreeSpaceForFastApiCall(masm, scratch1);
665 __ jmp(miss_label); 657 __ jmp(miss_label);
666 } 658 }
667 659
668 // Invoke a regular function. 660 // Invoke a regular function.
669 __ bind(&regular_invoke); 661 __ bind(&regular_invoke);
670 if (can_do_fast_api_call) { 662 if (can_do_fast_api_call) {
671 FreeSpaceForFastApiCall(masm, scratch1); 663 FreeSpaceForFastApiCall(masm, scratch1);
672 } 664 }
673 665
674 return true; 666 return HEAP->undefined_value(); // Success.
675 } 667 }
676 668
677 void CompileRegular(MacroAssembler* masm, 669 void CompileRegular(MacroAssembler* masm,
678 JSObject* object, 670 JSObject* object,
679 Register receiver, 671 Register receiver,
680 Register scratch1, 672 Register scratch1,
681 Register scratch2, 673 Register scratch2,
682 Register scratch3, 674 Register scratch3,
683 String* name, 675 String* name,
684 JSObject* interceptor_holder, 676 JSObject* interceptor_holder,
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after
1017 Register reg = 1009 Register reg =
1018 CheckPrototypes(object, receiver, holder, 1010 CheckPrototypes(object, receiver, holder,
1019 scratch1, scratch2, scratch3, name, miss); 1011 scratch1, scratch2, scratch3, name, miss);
1020 1012
1021 // Get the value from the properties. 1013 // Get the value from the properties.
1022 GenerateFastPropertyLoad(masm(), rax, reg, holder, index); 1014 GenerateFastPropertyLoad(masm(), rax, reg, holder, index);
1023 __ ret(0); 1015 __ ret(0);
1024 } 1016 }
1025 1017
1026 1018
1027 bool StubCompiler::GenerateLoadCallback(JSObject* object, 1019 MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
1028 JSObject* holder, 1020 JSObject* holder,
1029 Register receiver, 1021 Register receiver,
1030 Register name_reg, 1022 Register name_reg,
1031 Register scratch1, 1023 Register scratch1,
1032 Register scratch2, 1024 Register scratch2,
1033 Register scratch3, 1025 Register scratch3,
1034 AccessorInfo* callback, 1026 AccessorInfo* callback,
1035 String* name, 1027 String* name,
1036 Label* miss, 1028 Label* miss) {
1037 Failure** failure) {
1038 // Check that the receiver isn't a smi. 1029 // Check that the receiver isn't a smi.
1039 __ JumpIfSmi(receiver, miss); 1030 __ JumpIfSmi(receiver, miss);
1040 1031
1041 // Check that the maps haven't changed. 1032 // Check that the maps haven't changed.
1042 Register reg = 1033 Register reg =
1043 CheckPrototypes(object, receiver, holder, scratch1, 1034 CheckPrototypes(object, receiver, holder, scratch1,
1044 scratch2, scratch3, name, miss); 1035 scratch2, scratch3, name, miss);
1045 1036
1046 Handle<AccessorInfo> callback_handle(callback); 1037 Handle<AccessorInfo> callback_handle(callback);
1047 1038
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
1091 __ movq(StackSpaceOperand(0), rax); 1082 __ movq(StackSpaceOperand(0), rax);
1092 1083
1093 // The context register (rsi) has been saved in PrepareCallApiFunction and 1084 // The context register (rsi) has been saved in PrepareCallApiFunction and
1094 // could be used to pass arguments. 1085 // could be used to pass arguments.
1095 __ lea(accessor_info_arg, StackSpaceOperand(0)); 1086 __ lea(accessor_info_arg, StackSpaceOperand(0));
1096 1087
1097 // Emitting a stub call may try to allocate (if the code is not 1088 // Emitting a stub call may try to allocate (if the code is not
1098 // already generated). Do not allow the assembler to perform a 1089 // already generated). Do not allow the assembler to perform a
1099 // garbage collection but instead return the allocation failure 1090 // garbage collection but instead return the allocation failure
1100 // object. 1091 // object.
1101 MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); 1092 return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
1102 if (result->IsFailure()) {
1103 *failure = Failure::cast(result);
1104 return false;
1105 }
1106 return true;
1107 } 1093 }
1108 1094
1109 1095
1110 void StubCompiler::GenerateLoadConstant(JSObject* object, 1096 void StubCompiler::GenerateLoadConstant(JSObject* object,
1111 JSObject* holder, 1097 JSObject* holder,
1112 Register receiver, 1098 Register receiver,
1113 Register scratch1, 1099 Register scratch1,
1114 Register scratch2, 1100 Register scratch2,
1115 Register scratch3, 1101 Register scratch3,
1116 Object* value, 1102 Object* value,
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
1323 __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax); 1309 __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax);
1324 __ j(not_equal, miss); 1310 __ j(not_equal, miss);
1325 } else { 1311 } else {
1326 __ Cmp(rdi, Handle<JSFunction>(function)); 1312 __ Cmp(rdi, Handle<JSFunction>(function));
1327 __ j(not_equal, miss); 1313 __ j(not_equal, miss);
1328 } 1314 }
1329 } 1315 }
1330 1316
1331 1317
1332 MaybeObject* CallStubCompiler::GenerateMissBranch() { 1318 MaybeObject* CallStubCompiler::GenerateMissBranch() {
1333 MaybeObject* maybe_obj = Isolate::Current()->stub_cache()-> 1319 MaybeObject* maybe_obj = Isolate::Current()->stub_cache()->ComputeCallMiss(
1334 ComputeCallMiss(arguments().immediate(), kind_); 1320 arguments().immediate(), kind_);
1335 Object* obj; 1321 Object* obj;
1336 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1322 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1337 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); 1323 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
1338 return obj; 1324 return obj;
1339 } 1325 }
1340 1326
1341 1327
1342 MaybeObject* CallStubCompiler::CompileCallField(JSObject* object, 1328 MaybeObject* CallStubCompiler::CompileCallField(JSObject* object,
1343 JSObject* holder, 1329 JSObject* holder,
1344 int index, 1330 int index,
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after
1656 // -- ... 1642 // -- ...
1657 // -- rsp[(argc + 1) * 8] : receiver 1643 // -- rsp[(argc + 1) * 8] : receiver
1658 // ----------------------------------- 1644 // -----------------------------------
1659 1645
1660 // If object is not a string, bail out to regular call. 1646 // If object is not a string, bail out to regular call.
1661 if (!object->IsString() || cell != NULL) return HEAP->undefined_value(); 1647 if (!object->IsString() || cell != NULL) return HEAP->undefined_value();
1662 1648
1663 const int argc = arguments().immediate(); 1649 const int argc = arguments().immediate();
1664 1650
1665 Label miss; 1651 Label miss;
1652 Label name_miss;
1666 Label index_out_of_range; 1653 Label index_out_of_range;
1654 Label* index_out_of_range_label = &index_out_of_range;
1667 1655
1668 GenerateNameCheck(name, &miss); 1656 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
1657 index_out_of_range_label = &miss;
1658 }
1659
1660 GenerateNameCheck(name, &name_miss);
1669 1661
1670 // Check that the maps starting from the prototype haven't changed. 1662 // Check that the maps starting from the prototype haven't changed.
1671 GenerateDirectLoadGlobalFunctionPrototype(masm(), 1663 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1672 Context::STRING_FUNCTION_INDEX, 1664 Context::STRING_FUNCTION_INDEX,
1673 rax, 1665 rax,
1674 &miss); 1666 &miss);
1675 ASSERT(object != holder); 1667 ASSERT(object != holder);
1676 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 1668 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
1677 rbx, rdx, rdi, name, &miss); 1669 rbx, rdx, rdi, name, &miss);
1678 1670
1679 Register receiver = rbx; 1671 Register receiver = rbx;
1680 Register index = rdi; 1672 Register index = rdi;
1681 Register scratch = rdx; 1673 Register scratch = rdx;
1682 Register result = rax; 1674 Register result = rax;
1683 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); 1675 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
1684 if (argc > 0) { 1676 if (argc > 0) {
1685 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize)); 1677 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
1686 } else { 1678 } else {
1687 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); 1679 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1688 } 1680 }
1689 1681
1690 StringCharCodeAtGenerator char_code_at_generator(receiver, 1682 StringCharCodeAtGenerator char_code_at_generator(receiver,
1691 index, 1683 index,
1692 scratch, 1684 scratch,
1693 result, 1685 result,
1694 &miss, // When not a string. 1686 &miss, // When not a string.
1695 &miss, // When not a number. 1687 &miss, // When not a number.
1696 &index_out_of_range, 1688 index_out_of_range_label,
1697 STRING_INDEX_IS_NUMBER); 1689 STRING_INDEX_IS_NUMBER);
1698 char_code_at_generator.GenerateFast(masm()); 1690 char_code_at_generator.GenerateFast(masm());
1699 __ ret((argc + 1) * kPointerSize); 1691 __ ret((argc + 1) * kPointerSize);
1700 1692
1701 StubRuntimeCallHelper call_helper; 1693 StubRuntimeCallHelper call_helper;
1702 char_code_at_generator.GenerateSlow(masm(), call_helper); 1694 char_code_at_generator.GenerateSlow(masm(), call_helper);
1703 1695
1704 __ bind(&index_out_of_range); 1696 if (index_out_of_range.is_linked()) {
1705 __ LoadRoot(rax, Heap::kNanValueRootIndex); 1697 __ bind(&index_out_of_range);
1706 __ ret((argc + 1) * kPointerSize); 1698 __ LoadRoot(rax, Heap::kNanValueRootIndex);
1699 __ ret((argc + 1) * kPointerSize);
1700 }
1707 1701
1708 __ bind(&miss); 1702 __ bind(&miss);
1703 // Restore function name in rcx.
1704 __ Move(rcx, Handle<String>(name));
1705 __ bind(&name_miss);
1709 Object* obj; 1706 Object* obj;
1710 { MaybeObject* maybe_obj = GenerateMissBranch(); 1707 { MaybeObject* maybe_obj = GenerateMissBranch();
1711 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1708 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1712 } 1709 }
1713 1710
1714 // Return the generated code. 1711 // Return the generated code.
1715 return GetCode(function); 1712 return GetCode(function);
1716 } 1713 }
1717 1714
1718 1715
(...skipping 10 matching lines...) Expand all
1729 // -- ... 1726 // -- ...
1730 // -- rsp[(argc + 1) * 8] : receiver 1727 // -- rsp[(argc + 1) * 8] : receiver
1731 // ----------------------------------- 1728 // -----------------------------------
1732 1729
1733 // If object is not a string, bail out to regular call. 1730 // If object is not a string, bail out to regular call.
1734 if (!object->IsString() || cell != NULL) return HEAP->undefined_value(); 1731 if (!object->IsString() || cell != NULL) return HEAP->undefined_value();
1735 1732
1736 const int argc = arguments().immediate(); 1733 const int argc = arguments().immediate();
1737 1734
1738 Label miss; 1735 Label miss;
1736 Label name_miss;
1739 Label index_out_of_range; 1737 Label index_out_of_range;
1738 Label* index_out_of_range_label = &index_out_of_range;
1740 1739
1741 GenerateNameCheck(name, &miss); 1740 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
1741 index_out_of_range_label = &miss;
1742 }
1743
1744 GenerateNameCheck(name, &name_miss);
1742 1745
1743 // Check that the maps starting from the prototype haven't changed. 1746 // Check that the maps starting from the prototype haven't changed.
1744 GenerateDirectLoadGlobalFunctionPrototype(masm(), 1747 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1745 Context::STRING_FUNCTION_INDEX, 1748 Context::STRING_FUNCTION_INDEX,
1746 rax, 1749 rax,
1747 &miss); 1750 &miss);
1748 ASSERT(object != holder); 1751 ASSERT(object != holder);
1749 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, 1752 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
1750 rbx, rdx, rdi, name, &miss); 1753 rbx, rdx, rdi, name, &miss);
1751 1754
1752 Register receiver = rax; 1755 Register receiver = rax;
1753 Register index = rdi; 1756 Register index = rdi;
1754 Register scratch1 = rbx; 1757 Register scratch1 = rbx;
1755 Register scratch2 = rdx; 1758 Register scratch2 = rdx;
1756 Register result = rax; 1759 Register result = rax;
1757 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); 1760 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize));
1758 if (argc > 0) { 1761 if (argc > 0) {
1759 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize)); 1762 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize));
1760 } else { 1763 } else {
1761 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); 1764 __ LoadRoot(index, Heap::kUndefinedValueRootIndex);
1762 } 1765 }
1763 1766
1764 StringCharAtGenerator char_at_generator(receiver, 1767 StringCharAtGenerator char_at_generator(receiver,
1765 index, 1768 index,
1766 scratch1, 1769 scratch1,
1767 scratch2, 1770 scratch2,
1768 result, 1771 result,
1769 &miss, // When not a string. 1772 &miss, // When not a string.
1770 &miss, // When not a number. 1773 &miss, // When not a number.
1771 &index_out_of_range, 1774 index_out_of_range_label,
1772 STRING_INDEX_IS_NUMBER); 1775 STRING_INDEX_IS_NUMBER);
1773 char_at_generator.GenerateFast(masm()); 1776 char_at_generator.GenerateFast(masm());
1774 __ ret((argc + 1) * kPointerSize); 1777 __ ret((argc + 1) * kPointerSize);
1775 1778
1776 StubRuntimeCallHelper call_helper; 1779 StubRuntimeCallHelper call_helper;
1777 char_at_generator.GenerateSlow(masm(), call_helper); 1780 char_at_generator.GenerateSlow(masm(), call_helper);
1778 1781
1779 __ bind(&index_out_of_range); 1782 if (index_out_of_range.is_linked()) {
1780 __ LoadRoot(rax, Heap::kEmptyStringRootIndex); 1783 __ bind(&index_out_of_range);
1781 __ ret((argc + 1) * kPointerSize); 1784 __ LoadRoot(rax, Heap::kEmptyStringRootIndex);
1785 __ ret((argc + 1) * kPointerSize);
1786 }
1782 1787
1783 __ bind(&miss); 1788 __ bind(&miss);
1789 // Restore function name in rcx.
1790 __ Move(rcx, Handle<String>(name));
1791 __ bind(&name_miss);
1784 Object* obj; 1792 Object* obj;
1785 { MaybeObject* maybe_obj = GenerateMissBranch(); 1793 { MaybeObject* maybe_obj = GenerateMissBranch();
1786 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1794 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1787 } 1795 }
1788 1796
1789 // Return the generated code. 1797 // Return the generated code.
1790 return GetCode(function); 1798 return GetCode(function);
1791 } 1799 }
1792 1800
1793 1801
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
2109 rbx, rdx, rdi, name, &miss); 2117 rbx, rdx, rdi, name, &miss);
2110 } 2118 }
2111 break; 2119 break;
2112 } 2120 }
2113 2121
2114 default: 2122 default:
2115 UNREACHABLE(); 2123 UNREACHABLE();
2116 } 2124 }
2117 2125
2118 if (depth != kInvalidProtoDepth) { 2126 if (depth != kInvalidProtoDepth) {
2119 Failure* failure;
2120 // Move the return address on top of the stack. 2127 // Move the return address on top of the stack.
2121 __ movq(rax, Operand(rsp, 3 * kPointerSize)); 2128 __ movq(rax, Operand(rsp, 3 * kPointerSize));
2122 __ movq(Operand(rsp, 0 * kPointerSize), rax); 2129 __ movq(Operand(rsp, 0 * kPointerSize), rax);
2123 2130
2124 // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains 2131 // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains
2125 // duplicate of return address and will be overwritten. 2132 // duplicate of return address and will be overwritten.
2126 bool success = GenerateFastApiCall(masm(), optimization, argc, &failure); 2133 MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
2127 if (!success) { 2134 if (result->IsFailure()) return result;
2128 return failure;
2129 }
2130 } else { 2135 } else {
2131 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); 2136 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
2132 } 2137 }
2133 2138
2134 // Handle call cache miss. 2139 // Handle call cache miss.
2135 __ bind(&miss); 2140 __ bind(&miss);
2136 if (depth != kInvalidProtoDepth) { 2141 if (depth != kInvalidProtoDepth) {
2137 __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); 2142 __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
2138 } 2143 }
2139 2144
(...skipping 28 matching lines...) Expand all
2168 // Get the number of arguments. 2173 // Get the number of arguments.
2169 const int argc = arguments().immediate(); 2174 const int argc = arguments().immediate();
2170 2175
2171 LookupResult lookup; 2176 LookupResult lookup;
2172 LookupPostInterceptor(holder, name, &lookup); 2177 LookupPostInterceptor(holder, name, &lookup);
2173 2178
2174 // Get the receiver from the stack. 2179 // Get the receiver from the stack.
2175 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 2180 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2176 2181
2177 CallInterceptorCompiler compiler(this, arguments(), rcx); 2182 CallInterceptorCompiler compiler(this, arguments(), rcx);
2178 Failure* failure; 2183 MaybeObject* result = compiler.Compile(masm(),
2179 bool success = compiler.Compile(masm(), 2184 object,
2180 object, 2185 holder,
2181 holder, 2186 name,
2182 name, 2187 &lookup,
2183 &lookup, 2188 rdx,
2184 rdx, 2189 rbx,
2185 rbx, 2190 rdi,
2186 rdi, 2191 rax,
2187 rax, 2192 &miss);
2188 &miss, 2193 if (result->IsFailure()) return result;
2189 &failure);
2190 if (!success) {
2191 return failure;
2192 }
2193 2194
2194 // Restore receiver. 2195 // Restore receiver.
2195 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); 2196 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
2196 2197
2197 // Check that the function really is a function. 2198 // Check that the function really is a function.
2198 __ JumpIfSmi(rax, &miss); 2199 __ JumpIfSmi(rax, &miss);
2199 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); 2200 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
2200 __ j(not_equal, &miss); 2201 __ j(not_equal, &miss);
2201 2202
2202 // Patch the receiver on the stack with the global proxy if 2203 // Patch the receiver on the stack with the global proxy if
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
2258 GenerateGlobalReceiverCheck(object, holder, name, &miss); 2259 GenerateGlobalReceiverCheck(object, holder, name, &miss);
2259 2260
2260 GenerateLoadFunctionFromCell(cell, function, &miss); 2261 GenerateLoadFunctionFromCell(cell, function, &miss);
2261 2262
2262 // Patch the receiver on the stack with the global proxy. 2263 // Patch the receiver on the stack with the global proxy.
2263 if (object->IsGlobalObject()) { 2264 if (object->IsGlobalObject()) {
2264 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); 2265 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
2265 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); 2266 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx);
2266 } 2267 }
2267 2268
2268 // Setup the context (function already in edi). 2269 // Setup the context (function already in rdi).
2269 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); 2270 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
2270 2271
2271 // Jump to the cached code (tail call). 2272 // Jump to the cached code (tail call).
2272 __ IncrementCounter(COUNTERS->call_global_inline(), 1); 2273 __ IncrementCounter(COUNTERS->call_global_inline(), 1);
2273 ASSERT(function->is_compiled()); 2274 ASSERT(function->is_compiled());
2274 Handle<Code> code(function->code());
2275 ParameterCount expected(function->shared()->formal_parameter_count()); 2275 ParameterCount expected(function->shared()->formal_parameter_count());
2276 __ InvokeCode(code, expected, arguments(), 2276 if (V8::UseCrankshaft()) {
2277 RelocInfo::CODE_TARGET, JUMP_FUNCTION); 2277 // TODO(kasperl): For now, we always call indirectly through the
2278 2278 // code field in the function to allow recompilation to take effect
2279 // without changing any of the call sites.
2280 __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
2281 __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION);
2282 } else {
2283 Handle<Code> code(function->code());
2284 __ InvokeCode(code, expected, arguments(),
2285 RelocInfo::CODE_TARGET, JUMP_FUNCTION);
2286 }
2279 // Handle call cache miss. 2287 // Handle call cache miss.
2280 __ bind(&miss); 2288 __ bind(&miss);
2281 __ IncrementCounter(COUNTERS->call_global_inline_miss(), 1); 2289 __ IncrementCounter(COUNTERS->call_global_inline_miss(), 1);
2282 Object* obj; 2290 Object* obj;
2283 { MaybeObject* maybe_obj = GenerateMissBranch(); 2291 { MaybeObject* maybe_obj = GenerateMissBranch();
2284 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 2292 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2285 } 2293 }
2286 2294
2287 // Return the generated code. 2295 // Return the generated code.
2288 return GetCode(NORMAL, name); 2296 return GetCode(NORMAL, name);
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after
2621 JSObject* object, 2629 JSObject* object,
2622 JSObject* holder, 2630 JSObject* holder,
2623 AccessorInfo* callback) { 2631 AccessorInfo* callback) {
2624 // ----------- S t a t e ------------- 2632 // ----------- S t a t e -------------
2625 // -- rax : receiver 2633 // -- rax : receiver
2626 // -- rcx : name 2634 // -- rcx : name
2627 // -- rsp[0] : return address 2635 // -- rsp[0] : return address
2628 // ----------------------------------- 2636 // -----------------------------------
2629 Label miss; 2637 Label miss;
2630 2638
2631 Failure* failure = Failure::InternalError(); 2639 MaybeObject* result = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx,
2632 bool success = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, rdi, 2640 rdi, callback, name, &miss);
2633 callback, name, &miss, &failure); 2641 if (result->IsFailure()) {
2634 if (!success) {
2635 miss.Unuse(); 2642 miss.Unuse();
2636 return failure; 2643 return result;
2637 } 2644 }
2638 2645
2639 __ bind(&miss); 2646 __ bind(&miss);
2640 GenerateLoadMiss(masm(), Code::LOAD_IC); 2647 GenerateLoadMiss(masm(), Code::LOAD_IC);
2641 2648
2642 // Return the generated code. 2649 // Return the generated code.
2643 return GetCode(CALLBACKS, name); 2650 return GetCode(CALLBACKS, name);
2644 } 2651 }
2645 2652
2646 2653
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
2785 // -- rsp[0] : return address 2792 // -- rsp[0] : return address
2786 // ----------------------------------- 2793 // -----------------------------------
2787 Label miss; 2794 Label miss;
2788 2795
2789 __ IncrementCounter(COUNTERS->keyed_load_callback(), 1); 2796 __ IncrementCounter(COUNTERS->keyed_load_callback(), 1);
2790 2797
2791 // Check that the name has not changed. 2798 // Check that the name has not changed.
2792 __ Cmp(rax, Handle<String>(name)); 2799 __ Cmp(rax, Handle<String>(name));
2793 __ j(not_equal, &miss); 2800 __ j(not_equal, &miss);
2794 2801
2795 Failure* failure = Failure::InternalError(); 2802 MaybeObject* result = GenerateLoadCallback(receiver, holder, rdx, rax, rbx,
2796 bool success = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, rcx, rdi, 2803 rcx, rdi, callback, name, &miss);
2797 callback, name, &miss, &failure); 2804 if (result->IsFailure()) {
2798 if (!success) {
2799 miss.Unuse(); 2805 miss.Unuse();
2800 return failure; 2806 return result;
2801 } 2807 }
2802 2808
2803 __ bind(&miss); 2809 __ bind(&miss);
2804 2810
2805 __ DecrementCounter(COUNTERS->keyed_load_callback(), 1); 2811 __ DecrementCounter(COUNTERS->keyed_load_callback(), 1);
2806 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2812 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2807 2813
2808 // Return the generated code. 2814 // Return the generated code.
2809 return GetCode(CALLBACKS, name); 2815 return GetCode(CALLBACKS, name);
2810 } 2816 }
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
2906 // -- rsp[0] : return address 2912 // -- rsp[0] : return address
2907 // ----------------------------------- 2913 // -----------------------------------
2908 Label miss; 2914 Label miss;
2909 2915
2910 __ IncrementCounter(COUNTERS->keyed_load_string_length(), 1); 2916 __ IncrementCounter(COUNTERS->keyed_load_string_length(), 1);
2911 2917
2912 // Check that the name has not changed. 2918 // Check that the name has not changed.
2913 __ Cmp(rax, Handle<String>(name)); 2919 __ Cmp(rax, Handle<String>(name));
2914 __ j(not_equal, &miss); 2920 __ j(not_equal, &miss);
2915 2921
2916 GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss); 2922 GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss, true);
2917 __ bind(&miss); 2923 __ bind(&miss);
2918 __ DecrementCounter(COUNTERS->keyed_load_string_length(), 1); 2924 __ DecrementCounter(COUNTERS->keyed_load_string_length(), 1);
2919 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2925 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2920 2926
2921 // Return the generated code. 2927 // Return the generated code.
2922 return GetCode(CALLBACKS, name); 2928 return GetCode(CALLBACKS, name);
2923 } 2929 }
2924 2930
2925 2931
2926 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { 2932 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
3118 Code* code = Isolate::Current()->builtins()->builtin( 3124 Code* code = Isolate::Current()->builtins()->builtin(
3119 Builtins::JSConstructStubGeneric); 3125 Builtins::JSConstructStubGeneric);
3120 Handle<Code> generic_construct_stub(code); 3126 Handle<Code> generic_construct_stub(code);
3121 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); 3127 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
3122 3128
3123 // Return the generated code. 3129 // Return the generated code.
3124 return GetCode(); 3130 return GetCode();
3125 } 3131 }
3126 3132
3127 3133
3134 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
3135 ExternalArrayType array_type, Code::Flags flags) {
3136 // ----------- S t a t e -------------
3137 // -- rax : key
3138 // -- rdx : receiver
3139 // -- rsp[0] : return address
3140 // -----------------------------------
3141 Label slow;
3142
3143 // Check that the object isn't a smi.
3144 __ JumpIfSmi(rdx, &slow);
3145
3146 // Check that the key is a smi.
3147 __ JumpIfNotSmi(rax, &slow);
3148
3149 // Check that the object is a JS object.
3150 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
3151 __ j(not_equal, &slow);
3152 // Check that the receiver does not require access checks. We need
3153 // to check this explicitly since this generic stub does not perform
3154 // map checks. The map is already in rdx.
3155 __ testb(FieldOperand(rcx, Map::kBitFieldOffset),
3156 Immediate(1 << Map::kIsAccessCheckNeeded));
3157 __ j(not_zero, &slow);
3158
3159 // Check that the elements array is the appropriate type of
3160 // ExternalArray.
3161 // rax: index (as a smi)
3162 // rdx: JSObject
3163 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
3164 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
3165 HEAP->RootIndexForExternalArrayType(array_type));
3166 __ j(not_equal, &slow);
3167
3168 // Check that the index is in range.
3169 __ SmiToInteger32(rcx, rax);
3170 __ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset));
3171 // Unsigned comparison catches both negative and too-large values.
3172 __ j(above_equal, &slow);
3173
3174 // rax: index (as a smi)
3175 // rdx: receiver (JSObject)
3176 // rcx: untagged index
3177 // rbx: elements array
3178 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
3179 // rbx: base pointer of external storage
3180 switch (array_type) {
3181 case kExternalByteArray:
3182 __ movsxbq(rcx, Operand(rbx, rcx, times_1, 0));
3183 break;
3184 case kExternalUnsignedByteArray:
3185 __ movzxbq(rcx, Operand(rbx, rcx, times_1, 0));
3186 break;
3187 case kExternalShortArray:
3188 __ movsxwq(rcx, Operand(rbx, rcx, times_2, 0));
3189 break;
3190 case kExternalUnsignedShortArray:
3191 __ movzxwq(rcx, Operand(rbx, rcx, times_2, 0));
3192 break;
3193 case kExternalIntArray:
3194 __ movsxlq(rcx, Operand(rbx, rcx, times_4, 0));
3195 break;
3196 case kExternalUnsignedIntArray:
3197 __ movl(rcx, Operand(rbx, rcx, times_4, 0));
3198 break;
3199 case kExternalFloatArray:
3200 __ cvtss2sd(xmm0, Operand(rbx, rcx, times_4, 0));
3201 break;
3202 default:
3203 UNREACHABLE();
3204 break;
3205 }
3206
3207 // rax: index
3208 // rdx: receiver
3209 // For integer array types:
3210 // rcx: value
3211 // For floating-point array type:
3212 // xmm0: value as double.
3213
3214 ASSERT(kSmiValueSize == 32);
3215 if (array_type == kExternalUnsignedIntArray) {
3216 // For the UnsignedInt array type, we need to see whether
3217 // the value can be represented in a Smi. If not, we need to convert
3218 // it to a HeapNumber.
3219 NearLabel box_int;
3220
3221 __ JumpIfUIntNotValidSmiValue(rcx, &box_int);
3222
3223 __ Integer32ToSmi(rax, rcx);
3224 __ ret(0);
3225
3226 __ bind(&box_int);
3227
3228 // Allocate a HeapNumber for the int and perform int-to-double
3229 // conversion.
3230 // The value is zero-extended since we loaded the value from memory
3231 // with movl.
3232 __ cvtqsi2sd(xmm0, rcx);
3233
3234 __ AllocateHeapNumber(rcx, rbx, &slow);
3235 // Set the value.
3236 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
3237 __ movq(rax, rcx);
3238 __ ret(0);
3239 } else if (array_type == kExternalFloatArray) {
3240 // For the floating-point array type, we need to always allocate a
3241 // HeapNumber.
3242 __ AllocateHeapNumber(rcx, rbx, &slow);
3243 // Set the value.
3244 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0);
3245 __ movq(rax, rcx);
3246 __ ret(0);
3247 } else {
3248 __ Integer32ToSmi(rax, rcx);
3249 __ ret(0);
3250 }
3251
3252 // Slow case: Jump to runtime.
3253 __ bind(&slow);
3254 __ IncrementCounter(COUNTERS->keyed_load_external_array_slow(), 1);
3255
3256 // ----------- S t a t e -------------
3257 // -- rax : key
3258 // -- rdx : receiver
3259 // -- rsp[0] : return address
3260 // -----------------------------------
3261
3262 __ pop(rbx);
3263 __ push(rdx); // receiver
3264 __ push(rax); // name
3265 __ push(rbx); // return address
3266
3267 // Perform tail call to the entry.
3268 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3269
3270 // Return the generated code.
3271 return GetCode(flags);
3272 }
3273
3274
3275 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
3276 ExternalArrayType array_type, Code::Flags flags) {
3277 // ----------- S t a t e -------------
3278 // -- rax : value
3279 // -- rcx : key
3280 // -- rdx : receiver
3281 // -- rsp[0] : return address
3282 // -----------------------------------
3283 Label slow;
3284
3285 // Check that the object isn't a smi.
3286 __ JumpIfSmi(rdx, &slow);
3287 // Get the map from the receiver.
3288 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset));
3289 // Check that the receiver does not require access checks. We need
3290 // to do this because this generic stub does not perform map checks.
3291 __ testb(FieldOperand(rbx, Map::kBitFieldOffset),
3292 Immediate(1 << Map::kIsAccessCheckNeeded));
3293 __ j(not_zero, &slow);
3294 // Check that the key is a smi.
3295 __ JumpIfNotSmi(rcx, &slow);
3296
3297 // Check that the object is a JS object.
3298 __ CmpInstanceType(rbx, JS_OBJECT_TYPE);
3299 __ j(not_equal, &slow);
3300
3301 // Check that the elements array is the appropriate type of
3302 // ExternalArray.
3303 // rax: value
3304 // rcx: key (a smi)
3305 // rdx: receiver (a JSObject)
3306 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
3307 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset),
3308 HEAP->RootIndexForExternalArrayType(array_type));
3309 __ j(not_equal, &slow);
3310
3311 // Check that the index is in range.
3312 __ SmiToInteger32(rdi, rcx); // Untag the index.
3313 __ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset));
3314 // Unsigned comparison catches both negative and too-large values.
3315 __ j(above_equal, &slow);
3316
3317 // Handle both smis and HeapNumbers in the fast path. Go to the
3318 // runtime for all other kinds of values.
3319 // rax: value
3320 // rcx: key (a smi)
3321 // rdx: receiver (a JSObject)
3322 // rbx: elements array
3323 // rdi: untagged key
3324 NearLabel check_heap_number;
3325 __ JumpIfNotSmi(rax, &check_heap_number);
3326 // No more branches to slow case on this path. Key and receiver not needed.
3327 __ SmiToInteger32(rdx, rax);
3328 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
3329 // rbx: base pointer of external storage
3330 switch (array_type) {
3331 case kExternalByteArray:
3332 case kExternalUnsignedByteArray:
3333 __ movb(Operand(rbx, rdi, times_1, 0), rdx);
3334 break;
3335 case kExternalShortArray:
3336 case kExternalUnsignedShortArray:
3337 __ movw(Operand(rbx, rdi, times_2, 0), rdx);
3338 break;
3339 case kExternalIntArray:
3340 case kExternalUnsignedIntArray:
3341 __ movl(Operand(rbx, rdi, times_4, 0), rdx);
3342 break;
3343 case kExternalFloatArray:
3344 // Need to perform int-to-float conversion.
3345 __ cvtlsi2ss(xmm0, rdx);
3346 __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
3347 break;
3348 default:
3349 UNREACHABLE();
3350 break;
3351 }
3352 __ ret(0);
3353
3354 __ bind(&check_heap_number);
3355 // rax: value
3356 // rcx: key (a smi)
3357 // rdx: receiver (a JSObject)
3358 // rbx: elements array
3359 // rdi: untagged key
3360 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister);
3361 __ j(not_equal, &slow);
3362 // No more branches to slow case on this path.
3363
3364 // The WebGL specification leaves the behavior of storing NaN and
3365 // +/-Infinity into integer arrays basically undefined. For more
3366 // reproducible behavior, convert these to zero.
3367 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset));
3368 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset));
3369 // rdi: untagged index
3370 // rbx: base pointer of external storage
3371 // top of FPU stack: value
3372 if (array_type == kExternalFloatArray) {
3373 __ cvtsd2ss(xmm0, xmm0);
3374 __ movss(Operand(rbx, rdi, times_4, 0), xmm0);
3375 __ ret(0);
3376 } else {
3377 // Perform float-to-int conversion with truncation (round-to-zero)
3378 // behavior.
3379
3380 // Convert to int32 and store the low byte/word.
3381 // If the value is NaN or +/-infinity, the result is 0x80000000,
3382 // which is automatically zero when taken mod 2^n, n < 32.
3383 // rdx: value (converted to an untagged integer)
3384 // rdi: untagged index
3385 // rbx: base pointer of external storage
3386 switch (array_type) {
3387 case kExternalByteArray:
3388 case kExternalUnsignedByteArray:
3389 __ cvttsd2si(rdx, xmm0);
3390 __ movb(Operand(rbx, rdi, times_1, 0), rdx);
3391 break;
3392 case kExternalShortArray:
3393 case kExternalUnsignedShortArray:
3394 __ cvttsd2si(rdx, xmm0);
3395 __ movw(Operand(rbx, rdi, times_2, 0), rdx);
3396 break;
3397 case kExternalIntArray:
3398 case kExternalUnsignedIntArray: {
3399 // Convert to int64, so that NaN and infinities become
3400 // 0x8000000000000000, which is zero mod 2^32.
3401 __ cvttsd2siq(rdx, xmm0);
3402 __ movl(Operand(rbx, rdi, times_4, 0), rdx);
3403 break;
3404 }
3405 default:
3406 UNREACHABLE();
3407 break;
3408 }
3409 __ ret(0);
3410 }
3411
3412 // Slow case: call runtime.
3413 __ bind(&slow);
3414
3415 // ----------- S t a t e -------------
3416 // -- rax : value
3417 // -- rcx : key
3418 // -- rdx : receiver
3419 // -- rsp[0] : return address
3420 // -----------------------------------
3421
3422 __ pop(rbx);
3423 __ push(rdx); // receiver
3424 __ push(rcx); // key
3425 __ push(rax); // value
3426 __ push(rbx); // return address
3427
3428 // Do tail-call to runtime routine.
3429 __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
3430
3431 return GetCode(flags);
3432 }
3433
3128 #undef __ 3434 #undef __
3129 3435
3130 } } // namespace v8::internal 3436 } } // namespace v8::internal
3131 3437
3132 #endif // V8_TARGET_ARCH_X64 3438 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/macro-assembler-x64.cc ('k') | test/cctest/cctest.status » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698