| OLD | NEW |
| 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 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 ASSERT(kNotStringTag != 0); | 300 ASSERT(kNotStringTag != 0); |
| 301 __ testl(scratch, Immediate(kNotStringTag)); | 301 __ testl(scratch, Immediate(kNotStringTag)); |
| 302 __ j(not_zero, non_string_object); | 302 __ j(not_zero, non_string_object); |
| 303 } | 303 } |
| 304 | 304 |
| 305 | 305 |
| 306 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, | 306 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, |
| 307 Register receiver, | 307 Register receiver, |
| 308 Register scratch1, | 308 Register scratch1, |
| 309 Register scratch2, | 309 Register scratch2, |
| 310 Label* miss) { | 310 Label* miss, |
| 311 bool support_wrappers) { |
| 311 Label check_wrapper; | 312 Label check_wrapper; |
| 312 | 313 |
| 313 // Check if the object is a string leaving the instance type in the | 314 // Check if the object is a string leaving the instance type in the |
| 314 // scratch register. | 315 // scratch register. |
| 315 GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper); | 316 GenerateStringCheck(masm, receiver, scratch1, miss, |
| 317 support_wrappers ? &check_wrapper : miss); |
| 316 | 318 |
| 317 // Load length directly from the string. | 319 // Load length directly from the string. |
| 318 __ movq(rax, FieldOperand(receiver, String::kLengthOffset)); | 320 __ movq(rax, FieldOperand(receiver, String::kLengthOffset)); |
| 319 __ ret(0); | 321 __ ret(0); |
| 320 | 322 |
| 321 // Check if the object is a JSValue wrapper. | 323 if (support_wrappers) { |
| 322 __ bind(&check_wrapper); | 324 // Check if the object is a JSValue wrapper. |
| 323 __ cmpl(scratch1, Immediate(JS_VALUE_TYPE)); | 325 __ bind(&check_wrapper); |
| 324 __ j(not_equal, miss); | 326 __ cmpl(scratch1, Immediate(JS_VALUE_TYPE)); |
| 327 __ j(not_equal, miss); |
| 325 | 328 |
| 326 // Check if the wrapped value is a string and load the length | 329 // Check if the wrapped value is a string and load the length |
| 327 // directly if it is. | 330 // directly if it is. |
| 328 __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); | 331 __ movq(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); |
| 329 GenerateStringCheck(masm, scratch2, scratch1, miss, miss); | 332 GenerateStringCheck(masm, scratch2, scratch1, miss, miss); |
| 330 __ movq(rax, FieldOperand(scratch2, String::kLengthOffset)); | 333 __ movq(rax, FieldOperand(scratch2, String::kLengthOffset)); |
| 331 __ ret(0); | 334 __ ret(0); |
| 335 } |
| 332 } | 336 } |
| 333 | 337 |
| 334 | 338 |
| 335 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, | 339 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, |
| 336 Register receiver, | 340 Register receiver, |
| 337 Register result, | 341 Register result, |
| 338 Register scratch, | 342 Register scratch, |
| 339 Label* miss_label) { | 343 Label* miss_label) { |
| 340 __ TryGetFunctionPrototype(receiver, result, miss_label); | 344 __ TryGetFunctionPrototype(receiver, result, miss_label); |
| 341 if (!result.is(rax)) __ movq(rax, result); | 345 if (!result.is(rax)) __ movq(rax, result); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 // -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal | 434 // -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal |
| 431 // frame. | 435 // frame. |
| 432 // ----------------------------------- | 436 // ----------------------------------- |
| 433 __ movq(scratch, Operand(rsp, 0)); | 437 __ movq(scratch, Operand(rsp, 0)); |
| 434 __ movq(Operand(rsp, kFastApiCallArguments * kPointerSize), scratch); | 438 __ movq(Operand(rsp, kFastApiCallArguments * kPointerSize), scratch); |
| 435 __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments)); | 439 __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments)); |
| 436 } | 440 } |
| 437 | 441 |
| 438 | 442 |
| 439 // Generates call to API function. | 443 // Generates call to API function. |
| 440 static bool GenerateFastApiCall(MacroAssembler* masm, | 444 static MaybeObject* GenerateFastApiCall(MacroAssembler* masm, |
| 441 const CallOptimization& optimization, | 445 const CallOptimization& optimization, |
| 442 int argc, | 446 int argc) { |
| 443 Failure** failure) { | |
| 444 // ----------- S t a t e ------------- | 447 // ----------- S t a t e ------------- |
| 445 // -- rsp[0] : return address | 448 // -- rsp[0] : return address |
| 446 // -- rsp[8] : object passing the type check | 449 // -- rsp[8] : object passing the type check |
| 447 // (last fast api call extra argument, | 450 // (last fast api call extra argument, |
| 448 // set by CheckPrototypes) | 451 // set by CheckPrototypes) |
| 449 // -- rsp[16] : api function | 452 // -- rsp[16] : api function |
| 450 // (first fast api call extra argument) | 453 // (first fast api call extra argument) |
| 451 // -- rsp[24] : api call data | 454 // -- rsp[24] : api call data |
| 452 // -- rsp[32] : last argument | 455 // -- rsp[32] : last argument |
| 453 // -- ... | 456 // -- ... |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 __ Set(StackSpaceOperand(2), argc); // v8::Arguments::length_. | 500 __ Set(StackSpaceOperand(2), argc); // v8::Arguments::length_. |
| 498 // v8::Arguments::is_construct_call_. | 501 // v8::Arguments::is_construct_call_. |
| 499 __ Set(StackSpaceOperand(3), 0); | 502 __ Set(StackSpaceOperand(3), 0); |
| 500 | 503 |
| 501 // v8::InvocationCallback's argument. | 504 // v8::InvocationCallback's argument. |
| 502 __ lea(arguments_arg, StackSpaceOperand(0)); | 505 __ lea(arguments_arg, StackSpaceOperand(0)); |
| 503 // Emitting a stub call may try to allocate (if the code is not | 506 // Emitting a stub call may try to allocate (if the code is not |
| 504 // already generated). Do not allow the assembler to perform a | 507 // already generated). Do not allow the assembler to perform a |
| 505 // garbage collection but instead return the allocation failure | 508 // garbage collection but instead return the allocation failure |
| 506 // object. | 509 // object. |
| 507 MaybeObject* result = | 510 return masm->TryCallApiFunctionAndReturn(&fun, |
| 508 masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1); | 511 argc + kFastApiCallArguments + 1); |
| 509 if (result->IsFailure()) { | |
| 510 *failure = Failure::cast(result); | |
| 511 return false; | |
| 512 } | |
| 513 return true; | |
| 514 } | 512 } |
| 515 | 513 |
| 516 | 514 |
| 517 class CallInterceptorCompiler BASE_EMBEDDED { | 515 class CallInterceptorCompiler BASE_EMBEDDED { |
| 518 public: | 516 public: |
| 519 CallInterceptorCompiler(StubCompiler* stub_compiler, | 517 CallInterceptorCompiler(StubCompiler* stub_compiler, |
| 520 const ParameterCount& arguments, | 518 const ParameterCount& arguments, |
| 521 Register name) | 519 Register name) |
| 522 : stub_compiler_(stub_compiler), | 520 : stub_compiler_(stub_compiler), |
| 523 arguments_(arguments), | 521 arguments_(arguments), |
| 524 name_(name) {} | 522 name_(name) {} |
| 525 | 523 |
| 526 bool Compile(MacroAssembler* masm, | 524 MaybeObject* Compile(MacroAssembler* masm, |
| 527 JSObject* object, | 525 JSObject* object, |
| 528 JSObject* holder, | 526 JSObject* holder, |
| 529 String* name, | 527 String* name, |
| 530 LookupResult* lookup, | 528 LookupResult* lookup, |
| 531 Register receiver, | 529 Register receiver, |
| 532 Register scratch1, | 530 Register scratch1, |
| 533 Register scratch2, | 531 Register scratch2, |
| 534 Register scratch3, | 532 Register scratch3, |
| 535 Label* miss, | 533 Label* miss) { |
| 536 Failure** failure) { | |
| 537 ASSERT(holder->HasNamedInterceptor()); | 534 ASSERT(holder->HasNamedInterceptor()); |
| 538 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | 535 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 539 | 536 |
| 540 // Check that the receiver isn't a smi. | 537 // Check that the receiver isn't a smi. |
| 541 __ JumpIfSmi(receiver, miss); | 538 __ JumpIfSmi(receiver, miss); |
| 542 | 539 |
| 543 CallOptimization optimization(lookup); | 540 CallOptimization optimization(lookup); |
| 544 | 541 |
| 545 if (optimization.is_constant_call()) { | 542 if (optimization.is_constant_call()) { |
| 546 return CompileCacheable(masm, | 543 return CompileCacheable(masm, |
| 547 object, | 544 object, |
| 548 receiver, | 545 receiver, |
| 549 scratch1, | 546 scratch1, |
| 550 scratch2, | 547 scratch2, |
| 551 scratch3, | 548 scratch3, |
| 552 holder, | 549 holder, |
| 553 lookup, | 550 lookup, |
| 554 name, | 551 name, |
| 555 optimization, | 552 optimization, |
| 556 miss, | 553 miss); |
| 557 failure); | |
| 558 } else { | 554 } else { |
| 559 CompileRegular(masm, | 555 CompileRegular(masm, |
| 560 object, | 556 object, |
| 561 receiver, | 557 receiver, |
| 562 scratch1, | 558 scratch1, |
| 563 scratch2, | 559 scratch2, |
| 564 scratch3, | 560 scratch3, |
| 565 name, | 561 name, |
| 566 holder, | 562 holder, |
| 567 miss); | 563 miss); |
| 568 return true; | 564 return Heap::undefined_value(); // Success. |
| 569 } | 565 } |
| 570 } | 566 } |
| 571 | 567 |
| 572 private: | 568 private: |
| 573 bool CompileCacheable(MacroAssembler* masm, | 569 MaybeObject* CompileCacheable(MacroAssembler* masm, |
| 574 JSObject* object, | 570 JSObject* object, |
| 575 Register receiver, | 571 Register receiver, |
| 576 Register scratch1, | 572 Register scratch1, |
| 577 Register scratch2, | 573 Register scratch2, |
| 578 Register scratch3, | 574 Register scratch3, |
| 579 JSObject* interceptor_holder, | 575 JSObject* interceptor_holder, |
| 580 LookupResult* lookup, | 576 LookupResult* lookup, |
| 581 String* name, | 577 String* name, |
| 582 const CallOptimization& optimization, | 578 const CallOptimization& optimization, |
| 583 Label* miss_label, | 579 Label* miss_label) { |
| 584 Failure** failure) { | |
| 585 ASSERT(optimization.is_constant_call()); | 580 ASSERT(optimization.is_constant_call()); |
| 586 ASSERT(!lookup->holder()->IsGlobalObject()); | 581 ASSERT(!lookup->holder()->IsGlobalObject()); |
| 587 | 582 |
| 588 int depth1 = kInvalidProtoDepth; | 583 int depth1 = kInvalidProtoDepth; |
| 589 int depth2 = kInvalidProtoDepth; | 584 int depth2 = kInvalidProtoDepth; |
| 590 bool can_do_fast_api_call = false; | 585 bool can_do_fast_api_call = false; |
| 591 if (optimization.is_simple_api_call() && | 586 if (optimization.is_simple_api_call() && |
| 592 !lookup->holder()->IsGlobalObject()) { | 587 !lookup->holder()->IsGlobalObject()) { |
| 593 depth1 = | 588 depth1 = |
| 594 optimization.GetPrototypeDepthOfExpectedType(object, | 589 optimization.GetPrototypeDepthOfExpectedType(object, |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 636 } else { | 631 } else { |
| 637 // CheckPrototypes has a side effect of fetching a 'holder' | 632 // CheckPrototypes has a side effect of fetching a 'holder' |
| 638 // for API (object which is instanceof for the signature). It's | 633 // for API (object which is instanceof for the signature). It's |
| 639 // safe to omit it here, as if present, it should be fetched | 634 // safe to omit it here, as if present, it should be fetched |
| 640 // by the previous CheckPrototypes. | 635 // by the previous CheckPrototypes. |
| 641 ASSERT(depth2 == kInvalidProtoDepth); | 636 ASSERT(depth2 == kInvalidProtoDepth); |
| 642 } | 637 } |
| 643 | 638 |
| 644 // Invoke function. | 639 // Invoke function. |
| 645 if (can_do_fast_api_call) { | 640 if (can_do_fast_api_call) { |
| 646 bool success = GenerateFastApiCall(masm, | 641 MaybeObject* result = GenerateFastApiCall(masm, |
| 647 optimization, | 642 optimization, |
| 648 arguments_.immediate(), | 643 arguments_.immediate()); |
| 649 failure); | 644 if (result->IsFailure()) return result; |
| 650 if (!success) { | |
| 651 return false; | |
| 652 } | |
| 653 } else { | 645 } else { |
| 654 __ InvokeFunction(optimization.constant_function(), arguments_, | 646 __ InvokeFunction(optimization.constant_function(), arguments_, |
| 655 JUMP_FUNCTION); | 647 JUMP_FUNCTION); |
| 656 } | 648 } |
| 657 | 649 |
| 658 // Deferred code for fast API call case---clean preallocated space. | 650 // Deferred code for fast API call case---clean preallocated space. |
| 659 if (can_do_fast_api_call) { | 651 if (can_do_fast_api_call) { |
| 660 __ bind(&miss_cleanup); | 652 __ bind(&miss_cleanup); |
| 661 FreeSpaceForFastApiCall(masm, scratch1); | 653 FreeSpaceForFastApiCall(masm, scratch1); |
| 662 __ jmp(miss_label); | 654 __ jmp(miss_label); |
| 663 } | 655 } |
| 664 | 656 |
| 665 // Invoke a regular function. | 657 // Invoke a regular function. |
| 666 __ bind(®ular_invoke); | 658 __ bind(®ular_invoke); |
| 667 if (can_do_fast_api_call) { | 659 if (can_do_fast_api_call) { |
| 668 FreeSpaceForFastApiCall(masm, scratch1); | 660 FreeSpaceForFastApiCall(masm, scratch1); |
| 669 } | 661 } |
| 670 | 662 |
| 671 return true; | 663 return Heap::undefined_value(); // Success. |
| 672 } | 664 } |
| 673 | 665 |
| 674 void CompileRegular(MacroAssembler* masm, | 666 void CompileRegular(MacroAssembler* masm, |
| 675 JSObject* object, | 667 JSObject* object, |
| 676 Register receiver, | 668 Register receiver, |
| 677 Register scratch1, | 669 Register scratch1, |
| 678 Register scratch2, | 670 Register scratch2, |
| 679 Register scratch3, | 671 Register scratch3, |
| 680 String* name, | 672 String* name, |
| 681 JSObject* interceptor_holder, | 673 JSObject* interceptor_holder, |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1014 Register reg = | 1006 Register reg = |
| 1015 CheckPrototypes(object, receiver, holder, | 1007 CheckPrototypes(object, receiver, holder, |
| 1016 scratch1, scratch2, scratch3, name, miss); | 1008 scratch1, scratch2, scratch3, name, miss); |
| 1017 | 1009 |
| 1018 // Get the value from the properties. | 1010 // Get the value from the properties. |
| 1019 GenerateFastPropertyLoad(masm(), rax, reg, holder, index); | 1011 GenerateFastPropertyLoad(masm(), rax, reg, holder, index); |
| 1020 __ ret(0); | 1012 __ ret(0); |
| 1021 } | 1013 } |
| 1022 | 1014 |
| 1023 | 1015 |
| 1024 bool StubCompiler::GenerateLoadCallback(JSObject* object, | 1016 MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, |
| 1025 JSObject* holder, | 1017 JSObject* holder, |
| 1026 Register receiver, | 1018 Register receiver, |
| 1027 Register name_reg, | 1019 Register name_reg, |
| 1028 Register scratch1, | 1020 Register scratch1, |
| 1029 Register scratch2, | 1021 Register scratch2, |
| 1030 Register scratch3, | 1022 Register scratch3, |
| 1031 AccessorInfo* callback, | 1023 AccessorInfo* callback, |
| 1032 String* name, | 1024 String* name, |
| 1033 Label* miss, | 1025 Label* miss) { |
| 1034 Failure** failure) { | |
| 1035 // Check that the receiver isn't a smi. | 1026 // Check that the receiver isn't a smi. |
| 1036 __ JumpIfSmi(receiver, miss); | 1027 __ JumpIfSmi(receiver, miss); |
| 1037 | 1028 |
| 1038 // Check that the maps haven't changed. | 1029 // Check that the maps haven't changed. |
| 1039 Register reg = | 1030 Register reg = |
| 1040 CheckPrototypes(object, receiver, holder, scratch1, | 1031 CheckPrototypes(object, receiver, holder, scratch1, |
| 1041 scratch2, scratch3, name, miss); | 1032 scratch2, scratch3, name, miss); |
| 1042 | 1033 |
| 1043 Handle<AccessorInfo> callback_handle(callback); | 1034 Handle<AccessorInfo> callback_handle(callback); |
| 1044 | 1035 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1088 __ movq(StackSpaceOperand(0), rax); | 1079 __ movq(StackSpaceOperand(0), rax); |
| 1089 | 1080 |
| 1090 // The context register (rsi) has been saved in PrepareCallApiFunction and | 1081 // The context register (rsi) has been saved in PrepareCallApiFunction and |
| 1091 // could be used to pass arguments. | 1082 // could be used to pass arguments. |
| 1092 __ lea(accessor_info_arg, StackSpaceOperand(0)); | 1083 __ lea(accessor_info_arg, StackSpaceOperand(0)); |
| 1093 | 1084 |
| 1094 // Emitting a stub call may try to allocate (if the code is not | 1085 // Emitting a stub call may try to allocate (if the code is not |
| 1095 // already generated). Do not allow the assembler to perform a | 1086 // already generated). Do not allow the assembler to perform a |
| 1096 // garbage collection but instead return the allocation failure | 1087 // garbage collection but instead return the allocation failure |
| 1097 // object. | 1088 // object. |
| 1098 MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); | 1089 return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); |
| 1099 if (result->IsFailure()) { | |
| 1100 *failure = Failure::cast(result); | |
| 1101 return false; | |
| 1102 } | |
| 1103 return true; | |
| 1104 } | 1090 } |
| 1105 | 1091 |
| 1106 | 1092 |
| 1107 void StubCompiler::GenerateLoadConstant(JSObject* object, | 1093 void StubCompiler::GenerateLoadConstant(JSObject* object, |
| 1108 JSObject* holder, | 1094 JSObject* holder, |
| 1109 Register receiver, | 1095 Register receiver, |
| 1110 Register scratch1, | 1096 Register scratch1, |
| 1111 Register scratch2, | 1097 Register scratch2, |
| 1112 Register scratch3, | 1098 Register scratch3, |
| 1113 Object* value, | 1099 Object* value, |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1320 __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax); | 1306 __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax); |
| 1321 __ j(not_equal, miss); | 1307 __ j(not_equal, miss); |
| 1322 } else { | 1308 } else { |
| 1323 __ Cmp(rdi, Handle<JSFunction>(function)); | 1309 __ Cmp(rdi, Handle<JSFunction>(function)); |
| 1324 __ j(not_equal, miss); | 1310 __ j(not_equal, miss); |
| 1325 } | 1311 } |
| 1326 } | 1312 } |
| 1327 | 1313 |
| 1328 | 1314 |
| 1329 MaybeObject* CallStubCompiler::GenerateMissBranch() { | 1315 MaybeObject* CallStubCompiler::GenerateMissBranch() { |
| 1330 MaybeObject* maybe_obj = | 1316 MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(), |
| 1331 StubCache::ComputeCallMiss(arguments().immediate(), kind_); | 1317 kind_); |
| 1332 Object* obj; | 1318 Object* obj; |
| 1333 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1319 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 1334 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); | 1320 __ Jump(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); |
| 1335 return obj; | 1321 return obj; |
| 1336 } | 1322 } |
| 1337 | 1323 |
| 1338 | 1324 |
| 1339 MaybeObject* CallStubCompiler::CompileCallField(JSObject* object, | 1325 MaybeObject* CallStubCompiler::CompileCallField(JSObject* object, |
| 1340 JSObject* holder, | 1326 JSObject* holder, |
| 1341 int index, | 1327 int index, |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1653 // -- ... | 1639 // -- ... |
| 1654 // -- rsp[(argc + 1) * 8] : receiver | 1640 // -- rsp[(argc + 1) * 8] : receiver |
| 1655 // ----------------------------------- | 1641 // ----------------------------------- |
| 1656 | 1642 |
| 1657 // If object is not a string, bail out to regular call. | 1643 // If object is not a string, bail out to regular call. |
| 1658 if (!object->IsString() || cell != NULL) return Heap::undefined_value(); | 1644 if (!object->IsString() || cell != NULL) return Heap::undefined_value(); |
| 1659 | 1645 |
| 1660 const int argc = arguments().immediate(); | 1646 const int argc = arguments().immediate(); |
| 1661 | 1647 |
| 1662 Label miss; | 1648 Label miss; |
| 1649 Label name_miss; |
| 1663 Label index_out_of_range; | 1650 Label index_out_of_range; |
| 1651 Label* index_out_of_range_label = &index_out_of_range; |
| 1664 | 1652 |
| 1665 GenerateNameCheck(name, &miss); | 1653 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { |
| 1654 index_out_of_range_label = &miss; |
| 1655 } |
| 1656 |
| 1657 GenerateNameCheck(name, &name_miss); |
| 1666 | 1658 |
| 1667 // Check that the maps starting from the prototype haven't changed. | 1659 // Check that the maps starting from the prototype haven't changed. |
| 1668 GenerateDirectLoadGlobalFunctionPrototype(masm(), | 1660 GenerateDirectLoadGlobalFunctionPrototype(masm(), |
| 1669 Context::STRING_FUNCTION_INDEX, | 1661 Context::STRING_FUNCTION_INDEX, |
| 1670 rax, | 1662 rax, |
| 1671 &miss); | 1663 &miss); |
| 1672 ASSERT(object != holder); | 1664 ASSERT(object != holder); |
| 1673 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, | 1665 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, |
| 1674 rbx, rdx, rdi, name, &miss); | 1666 rbx, rdx, rdi, name, &miss); |
| 1675 | 1667 |
| 1676 Register receiver = rbx; | 1668 Register receiver = rbx; |
| 1677 Register index = rdi; | 1669 Register index = rdi; |
| 1678 Register scratch = rdx; | 1670 Register scratch = rdx; |
| 1679 Register result = rax; | 1671 Register result = rax; |
| 1680 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); | 1672 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); |
| 1681 if (argc > 0) { | 1673 if (argc > 0) { |
| 1682 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize)); | 1674 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize)); |
| 1683 } else { | 1675 } else { |
| 1684 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); | 1676 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); |
| 1685 } | 1677 } |
| 1686 | 1678 |
| 1687 StringCharCodeAtGenerator char_code_at_generator(receiver, | 1679 StringCharCodeAtGenerator char_code_at_generator(receiver, |
| 1688 index, | 1680 index, |
| 1689 scratch, | 1681 scratch, |
| 1690 result, | 1682 result, |
| 1691 &miss, // When not a string. | 1683 &miss, // When not a string. |
| 1692 &miss, // When not a number. | 1684 &miss, // When not a number. |
| 1693 &index_out_of_range, | 1685 index_out_of_range_label, |
| 1694 STRING_INDEX_IS_NUMBER); | 1686 STRING_INDEX_IS_NUMBER); |
| 1695 char_code_at_generator.GenerateFast(masm()); | 1687 char_code_at_generator.GenerateFast(masm()); |
| 1696 __ ret((argc + 1) * kPointerSize); | 1688 __ ret((argc + 1) * kPointerSize); |
| 1697 | 1689 |
| 1698 StubRuntimeCallHelper call_helper; | 1690 StubRuntimeCallHelper call_helper; |
| 1699 char_code_at_generator.GenerateSlow(masm(), call_helper); | 1691 char_code_at_generator.GenerateSlow(masm(), call_helper); |
| 1700 | 1692 |
| 1701 __ bind(&index_out_of_range); | 1693 if (index_out_of_range.is_linked()) { |
| 1702 __ LoadRoot(rax, Heap::kNanValueRootIndex); | 1694 __ bind(&index_out_of_range); |
| 1703 __ ret((argc + 1) * kPointerSize); | 1695 __ LoadRoot(rax, Heap::kNanValueRootIndex); |
| 1696 __ ret((argc + 1) * kPointerSize); |
| 1697 } |
| 1704 | 1698 |
| 1705 __ bind(&miss); | 1699 __ bind(&miss); |
| 1700 // Restore function name in rcx. |
| 1701 __ Move(rcx, Handle<String>(name)); |
| 1702 __ bind(&name_miss); |
| 1706 Object* obj; | 1703 Object* obj; |
| 1707 { MaybeObject* maybe_obj = GenerateMissBranch(); | 1704 { MaybeObject* maybe_obj = GenerateMissBranch(); |
| 1708 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1705 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 1709 } | 1706 } |
| 1710 | 1707 |
| 1711 // Return the generated code. | 1708 // Return the generated code. |
| 1712 return GetCode(function); | 1709 return GetCode(function); |
| 1713 } | 1710 } |
| 1714 | 1711 |
| 1715 | 1712 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1726 // -- ... | 1723 // -- ... |
| 1727 // -- rsp[(argc + 1) * 8] : receiver | 1724 // -- rsp[(argc + 1) * 8] : receiver |
| 1728 // ----------------------------------- | 1725 // ----------------------------------- |
| 1729 | 1726 |
| 1730 // If object is not a string, bail out to regular call. | 1727 // If object is not a string, bail out to regular call. |
| 1731 if (!object->IsString() || cell != NULL) return Heap::undefined_value(); | 1728 if (!object->IsString() || cell != NULL) return Heap::undefined_value(); |
| 1732 | 1729 |
| 1733 const int argc = arguments().immediate(); | 1730 const int argc = arguments().immediate(); |
| 1734 | 1731 |
| 1735 Label miss; | 1732 Label miss; |
| 1733 Label name_miss; |
| 1736 Label index_out_of_range; | 1734 Label index_out_of_range; |
| 1735 Label* index_out_of_range_label = &index_out_of_range; |
| 1737 | 1736 |
| 1738 GenerateNameCheck(name, &miss); | 1737 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { |
| 1738 index_out_of_range_label = &miss; |
| 1739 } |
| 1740 |
| 1741 GenerateNameCheck(name, &name_miss); |
| 1739 | 1742 |
| 1740 // Check that the maps starting from the prototype haven't changed. | 1743 // Check that the maps starting from the prototype haven't changed. |
| 1741 GenerateDirectLoadGlobalFunctionPrototype(masm(), | 1744 GenerateDirectLoadGlobalFunctionPrototype(masm(), |
| 1742 Context::STRING_FUNCTION_INDEX, | 1745 Context::STRING_FUNCTION_INDEX, |
| 1743 rax, | 1746 rax, |
| 1744 &miss); | 1747 &miss); |
| 1745 ASSERT(object != holder); | 1748 ASSERT(object != holder); |
| 1746 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, | 1749 CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, |
| 1747 rbx, rdx, rdi, name, &miss); | 1750 rbx, rdx, rdi, name, &miss); |
| 1748 | 1751 |
| 1749 Register receiver = rax; | 1752 Register receiver = rax; |
| 1750 Register index = rdi; | 1753 Register index = rdi; |
| 1751 Register scratch1 = rbx; | 1754 Register scratch1 = rbx; |
| 1752 Register scratch2 = rdx; | 1755 Register scratch2 = rdx; |
| 1753 Register result = rax; | 1756 Register result = rax; |
| 1754 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); | 1757 __ movq(receiver, Operand(rsp, (argc + 1) * kPointerSize)); |
| 1755 if (argc > 0) { | 1758 if (argc > 0) { |
| 1756 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize)); | 1759 __ movq(index, Operand(rsp, (argc - 0) * kPointerSize)); |
| 1757 } else { | 1760 } else { |
| 1758 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); | 1761 __ LoadRoot(index, Heap::kUndefinedValueRootIndex); |
| 1759 } | 1762 } |
| 1760 | 1763 |
| 1761 StringCharAtGenerator char_at_generator(receiver, | 1764 StringCharAtGenerator char_at_generator(receiver, |
| 1762 index, | 1765 index, |
| 1763 scratch1, | 1766 scratch1, |
| 1764 scratch2, | 1767 scratch2, |
| 1765 result, | 1768 result, |
| 1766 &miss, // When not a string. | 1769 &miss, // When not a string. |
| 1767 &miss, // When not a number. | 1770 &miss, // When not a number. |
| 1768 &index_out_of_range, | 1771 index_out_of_range_label, |
| 1769 STRING_INDEX_IS_NUMBER); | 1772 STRING_INDEX_IS_NUMBER); |
| 1770 char_at_generator.GenerateFast(masm()); | 1773 char_at_generator.GenerateFast(masm()); |
| 1771 __ ret((argc + 1) * kPointerSize); | 1774 __ ret((argc + 1) * kPointerSize); |
| 1772 | 1775 |
| 1773 StubRuntimeCallHelper call_helper; | 1776 StubRuntimeCallHelper call_helper; |
| 1774 char_at_generator.GenerateSlow(masm(), call_helper); | 1777 char_at_generator.GenerateSlow(masm(), call_helper); |
| 1775 | 1778 |
| 1776 __ bind(&index_out_of_range); | 1779 if (index_out_of_range.is_linked()) { |
| 1777 __ LoadRoot(rax, Heap::kEmptyStringRootIndex); | 1780 __ bind(&index_out_of_range); |
| 1778 __ ret((argc + 1) * kPointerSize); | 1781 __ LoadRoot(rax, Heap::kEmptyStringRootIndex); |
| 1782 __ ret((argc + 1) * kPointerSize); |
| 1783 } |
| 1779 | 1784 |
| 1780 __ bind(&miss); | 1785 __ bind(&miss); |
| 1786 // Restore function name in rcx. |
| 1787 __ Move(rcx, Handle<String>(name)); |
| 1788 __ bind(&name_miss); |
| 1781 Object* obj; | 1789 Object* obj; |
| 1782 { MaybeObject* maybe_obj = GenerateMissBranch(); | 1790 { MaybeObject* maybe_obj = GenerateMissBranch(); |
| 1783 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1791 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 1784 } | 1792 } |
| 1785 | 1793 |
| 1786 // Return the generated code. | 1794 // Return the generated code. |
| 1787 return GetCode(function); | 1795 return GetCode(function); |
| 1788 } | 1796 } |
| 1789 | 1797 |
| 1790 | 1798 |
| (...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2106 rbx, rdx, rdi, name, &miss); | 2114 rbx, rdx, rdi, name, &miss); |
| 2107 } | 2115 } |
| 2108 break; | 2116 break; |
| 2109 } | 2117 } |
| 2110 | 2118 |
| 2111 default: | 2119 default: |
| 2112 UNREACHABLE(); | 2120 UNREACHABLE(); |
| 2113 } | 2121 } |
| 2114 | 2122 |
| 2115 if (depth != kInvalidProtoDepth) { | 2123 if (depth != kInvalidProtoDepth) { |
| 2116 Failure* failure; | |
| 2117 // Move the return address on top of the stack. | 2124 // Move the return address on top of the stack. |
| 2118 __ movq(rax, Operand(rsp, 3 * kPointerSize)); | 2125 __ movq(rax, Operand(rsp, 3 * kPointerSize)); |
| 2119 __ movq(Operand(rsp, 0 * kPointerSize), rax); | 2126 __ movq(Operand(rsp, 0 * kPointerSize), rax); |
| 2120 | 2127 |
| 2121 // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains | 2128 // rsp[2 * kPointerSize] is uninitialized, rsp[3 * kPointerSize] contains |
| 2122 // duplicate of return address and will be overwritten. | 2129 // duplicate of return address and will be overwritten. |
| 2123 bool success = GenerateFastApiCall(masm(), optimization, argc, &failure); | 2130 MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc); |
| 2124 if (!success) { | 2131 if (result->IsFailure()) return result; |
| 2125 return failure; | |
| 2126 } | |
| 2127 } else { | 2132 } else { |
| 2128 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); | 2133 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); |
| 2129 } | 2134 } |
| 2130 | 2135 |
| 2131 // Handle call cache miss. | 2136 // Handle call cache miss. |
| 2132 __ bind(&miss); | 2137 __ bind(&miss); |
| 2133 if (depth != kInvalidProtoDepth) { | 2138 if (depth != kInvalidProtoDepth) { |
| 2134 __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); | 2139 __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); |
| 2135 } | 2140 } |
| 2136 | 2141 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2165 // Get the number of arguments. | 2170 // Get the number of arguments. |
| 2166 const int argc = arguments().immediate(); | 2171 const int argc = arguments().immediate(); |
| 2167 | 2172 |
| 2168 LookupResult lookup; | 2173 LookupResult lookup; |
| 2169 LookupPostInterceptor(holder, name, &lookup); | 2174 LookupPostInterceptor(holder, name, &lookup); |
| 2170 | 2175 |
| 2171 // Get the receiver from the stack. | 2176 // Get the receiver from the stack. |
| 2172 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); | 2177 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
| 2173 | 2178 |
| 2174 CallInterceptorCompiler compiler(this, arguments(), rcx); | 2179 CallInterceptorCompiler compiler(this, arguments(), rcx); |
| 2175 Failure* failure; | 2180 MaybeObject* result = compiler.Compile(masm(), |
| 2176 bool success = compiler.Compile(masm(), | 2181 object, |
| 2177 object, | 2182 holder, |
| 2178 holder, | 2183 name, |
| 2179 name, | 2184 &lookup, |
| 2180 &lookup, | 2185 rdx, |
| 2181 rdx, | 2186 rbx, |
| 2182 rbx, | 2187 rdi, |
| 2183 rdi, | 2188 rax, |
| 2184 rax, | 2189 &miss); |
| 2185 &miss, | 2190 if (result->IsFailure()) return result; |
| 2186 &failure); | |
| 2187 if (!success) { | |
| 2188 return failure; | |
| 2189 } | |
| 2190 | 2191 |
| 2191 // Restore receiver. | 2192 // Restore receiver. |
| 2192 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); | 2193 __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); |
| 2193 | 2194 |
| 2194 // Check that the function really is a function. | 2195 // Check that the function really is a function. |
| 2195 __ JumpIfSmi(rax, &miss); | 2196 __ JumpIfSmi(rax, &miss); |
| 2196 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); | 2197 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); |
| 2197 __ j(not_equal, &miss); | 2198 __ j(not_equal, &miss); |
| 2198 | 2199 |
| 2199 // Patch the receiver on the stack with the global proxy if | 2200 // Patch the receiver on the stack with the global proxy if |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2255 GenerateGlobalReceiverCheck(object, holder, name, &miss); | 2256 GenerateGlobalReceiverCheck(object, holder, name, &miss); |
| 2256 | 2257 |
| 2257 GenerateLoadFunctionFromCell(cell, function, &miss); | 2258 GenerateLoadFunctionFromCell(cell, function, &miss); |
| 2258 | 2259 |
| 2259 // Patch the receiver on the stack with the global proxy. | 2260 // Patch the receiver on the stack with the global proxy. |
| 2260 if (object->IsGlobalObject()) { | 2261 if (object->IsGlobalObject()) { |
| 2261 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); | 2262 __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); |
| 2262 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); | 2263 __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); |
| 2263 } | 2264 } |
| 2264 | 2265 |
| 2265 // Setup the context (function already in edi). | 2266 // Setup the context (function already in rdi). |
| 2266 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); | 2267 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
| 2267 | 2268 |
| 2268 // Jump to the cached code (tail call). | 2269 // Jump to the cached code (tail call). |
| 2269 __ IncrementCounter(&Counters::call_global_inline, 1); | 2270 __ IncrementCounter(&Counters::call_global_inline, 1); |
| 2270 ASSERT(function->is_compiled()); | 2271 ASSERT(function->is_compiled()); |
| 2271 Handle<Code> code(function->code()); | |
| 2272 ParameterCount expected(function->shared()->formal_parameter_count()); | 2272 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 2273 __ InvokeCode(code, expected, arguments(), | 2273 if (V8::UseCrankshaft()) { |
| 2274 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | 2274 // TODO(kasperl): For now, we always call indirectly through the |
| 2275 | 2275 // code field in the function to allow recompilation to take effect |
| 2276 // without changing any of the call sites. |
| 2277 __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset)); |
| 2278 __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION); |
| 2279 } else { |
| 2280 Handle<Code> code(function->code()); |
| 2281 __ InvokeCode(code, expected, arguments(), |
| 2282 RelocInfo::CODE_TARGET, JUMP_FUNCTION); |
| 2283 } |
| 2276 // Handle call cache miss. | 2284 // Handle call cache miss. |
| 2277 __ bind(&miss); | 2285 __ bind(&miss); |
| 2278 __ IncrementCounter(&Counters::call_global_inline_miss, 1); | 2286 __ IncrementCounter(&Counters::call_global_inline_miss, 1); |
| 2279 Object* obj; | 2287 Object* obj; |
| 2280 { MaybeObject* maybe_obj = GenerateMissBranch(); | 2288 { MaybeObject* maybe_obj = GenerateMissBranch(); |
| 2281 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 2289 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 2282 } | 2290 } |
| 2283 | 2291 |
| 2284 // Return the generated code. | 2292 // Return the generated code. |
| 2285 return GetCode(NORMAL, name); | 2293 return GetCode(NORMAL, name); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2423 // -- rdx : receiver | 2431 // -- rdx : receiver |
| 2424 // -- rsp[0] : return address | 2432 // -- rsp[0] : return address |
| 2425 // ----------------------------------- | 2433 // ----------------------------------- |
| 2426 Label miss; | 2434 Label miss; |
| 2427 | 2435 |
| 2428 // Check that the map of the global has not changed. | 2436 // Check that the map of the global has not changed. |
| 2429 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), | 2437 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), |
| 2430 Handle<Map>(object->map())); | 2438 Handle<Map>(object->map())); |
| 2431 __ j(not_equal, &miss); | 2439 __ j(not_equal, &miss); |
| 2432 | 2440 |
| 2441 // Check that the value in the cell is not the hole. If it is, this |
| 2442 // cell could have been deleted and reintroducing the global needs |
| 2443 // to update the property details in the property dictionary of the |
| 2444 // global object. We bail out to the runtime system to do that. |
| 2445 __ Move(rbx, Handle<JSGlobalPropertyCell>(cell)); |
| 2446 __ CompareRoot(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), |
| 2447 Heap::kTheHoleValueRootIndex); |
| 2448 __ j(equal, &miss); |
| 2449 |
| 2433 // Store the value in the cell. | 2450 // Store the value in the cell. |
| 2434 __ Move(rcx, Handle<JSGlobalPropertyCell>(cell)); | 2451 __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), rax); |
| 2435 __ movq(FieldOperand(rcx, JSGlobalPropertyCell::kValueOffset), rax); | |
| 2436 | 2452 |
| 2437 // Return the value (register rax). | 2453 // Return the value (register rax). |
| 2438 __ IncrementCounter(&Counters::named_store_global_inline, 1); | 2454 __ IncrementCounter(&Counters::named_store_global_inline, 1); |
| 2439 __ ret(0); | 2455 __ ret(0); |
| 2440 | 2456 |
| 2441 // Handle store cache miss. | 2457 // Handle store cache miss. |
| 2442 __ bind(&miss); | 2458 __ bind(&miss); |
| 2443 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1); | 2459 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1); |
| 2444 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 2460 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); |
| 2445 __ Jump(ic, RelocInfo::CODE_TARGET); | 2461 __ Jump(ic, RelocInfo::CODE_TARGET); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2536 // Handle store cache miss. | 2552 // Handle store cache miss. |
| 2537 __ bind(&miss); | 2553 __ bind(&miss); |
| 2538 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); | 2554 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); |
| 2539 __ jmp(ic, RelocInfo::CODE_TARGET); | 2555 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2540 | 2556 |
| 2541 // Return the generated code. | 2557 // Return the generated code. |
| 2542 return GetCode(NORMAL, NULL); | 2558 return GetCode(NORMAL, NULL); |
| 2543 } | 2559 } |
| 2544 | 2560 |
| 2545 | 2561 |
| 2562 MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray( |
| 2563 JSObject* receiver) { |
| 2564 // ----------- S t a t e ------------- |
| 2565 // -- rax : value |
| 2566 // -- rcx : key |
| 2567 // -- rdx : receiver |
| 2568 // -- rsp[0] : return address |
| 2569 // ----------------------------------- |
| 2570 Label miss; |
| 2571 |
| 2572 // Check that the map matches. |
| 2573 __ CheckMap(rdx, Handle<Map>(receiver->map()), &miss, false); |
| 2574 |
| 2575 // Do the load. |
| 2576 GenerateFastPixelArrayStore(masm(), |
| 2577 rdx, |
| 2578 rcx, |
| 2579 rax, |
| 2580 rdi, |
| 2581 rbx, |
| 2582 true, |
| 2583 false, |
| 2584 &miss, |
| 2585 &miss, |
| 2586 NULL, |
| 2587 &miss); |
| 2588 |
| 2589 // Handle store cache miss. |
| 2590 __ bind(&miss); |
| 2591 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); |
| 2592 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2593 |
| 2594 // Return the generated code. |
| 2595 return GetCode(NORMAL, NULL); |
| 2596 } |
| 2597 |
| 2598 |
| 2546 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, | 2599 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, |
| 2547 JSObject* object, | 2600 JSObject* object, |
| 2548 JSObject* last) { | 2601 JSObject* last) { |
| 2549 // ----------- S t a t e ------------- | 2602 // ----------- S t a t e ------------- |
| 2550 // -- rax : receiver | 2603 // -- rax : receiver |
| 2551 // -- rcx : name | 2604 // -- rcx : name |
| 2552 // -- rsp[0] : return address | 2605 // -- rsp[0] : return address |
| 2553 // ----------------------------------- | 2606 // ----------------------------------- |
| 2554 Label miss; | 2607 Label miss; |
| 2555 | 2608 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2612 JSObject* object, | 2665 JSObject* object, |
| 2613 JSObject* holder, | 2666 JSObject* holder, |
| 2614 AccessorInfo* callback) { | 2667 AccessorInfo* callback) { |
| 2615 // ----------- S t a t e ------------- | 2668 // ----------- S t a t e ------------- |
| 2616 // -- rax : receiver | 2669 // -- rax : receiver |
| 2617 // -- rcx : name | 2670 // -- rcx : name |
| 2618 // -- rsp[0] : return address | 2671 // -- rsp[0] : return address |
| 2619 // ----------------------------------- | 2672 // ----------------------------------- |
| 2620 Label miss; | 2673 Label miss; |
| 2621 | 2674 |
| 2622 Failure* failure = Failure::InternalError(); | 2675 MaybeObject* result = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, |
| 2623 bool success = GenerateLoadCallback(object, holder, rax, rcx, rdx, rbx, rdi, | 2676 rdi, callback, name, &miss); |
| 2624 callback, name, &miss, &failure); | 2677 if (result->IsFailure()) { |
| 2625 if (!success) { | |
| 2626 miss.Unuse(); | 2678 miss.Unuse(); |
| 2627 return failure; | 2679 return result; |
| 2628 } | 2680 } |
| 2629 | 2681 |
| 2630 __ bind(&miss); | 2682 __ bind(&miss); |
| 2631 GenerateLoadMiss(masm(), Code::LOAD_IC); | 2683 GenerateLoadMiss(masm(), Code::LOAD_IC); |
| 2632 | 2684 |
| 2633 // Return the generated code. | 2685 // Return the generated code. |
| 2634 return GetCode(CALLBACKS, name); | 2686 return GetCode(CALLBACKS, name); |
| 2635 } | 2687 } |
| 2636 | 2688 |
| 2637 | 2689 |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2776 // -- rsp[0] : return address | 2828 // -- rsp[0] : return address |
| 2777 // ----------------------------------- | 2829 // ----------------------------------- |
| 2778 Label miss; | 2830 Label miss; |
| 2779 | 2831 |
| 2780 __ IncrementCounter(&Counters::keyed_load_callback, 1); | 2832 __ IncrementCounter(&Counters::keyed_load_callback, 1); |
| 2781 | 2833 |
| 2782 // Check that the name has not changed. | 2834 // Check that the name has not changed. |
| 2783 __ Cmp(rax, Handle<String>(name)); | 2835 __ Cmp(rax, Handle<String>(name)); |
| 2784 __ j(not_equal, &miss); | 2836 __ j(not_equal, &miss); |
| 2785 | 2837 |
| 2786 Failure* failure = Failure::InternalError(); | 2838 MaybeObject* result = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, |
| 2787 bool success = GenerateLoadCallback(receiver, holder, rdx, rax, rbx, rcx, rdi, | 2839 rcx, rdi, callback, name, &miss); |
| 2788 callback, name, &miss, &failure); | 2840 if (result->IsFailure()) { |
| 2789 if (!success) { | |
| 2790 miss.Unuse(); | 2841 miss.Unuse(); |
| 2791 return failure; | 2842 return result; |
| 2792 } | 2843 } |
| 2793 | 2844 |
| 2794 __ bind(&miss); | 2845 __ bind(&miss); |
| 2795 | 2846 |
| 2796 __ DecrementCounter(&Counters::keyed_load_callback, 1); | 2847 __ DecrementCounter(&Counters::keyed_load_callback, 1); |
| 2797 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 2848 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 2798 | 2849 |
| 2799 // Return the generated code. | 2850 // Return the generated code. |
| 2800 return GetCode(CALLBACKS, name); | 2851 return GetCode(CALLBACKS, name); |
| 2801 } | 2852 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2897 // -- rsp[0] : return address | 2948 // -- rsp[0] : return address |
| 2898 // ----------------------------------- | 2949 // ----------------------------------- |
| 2899 Label miss; | 2950 Label miss; |
| 2900 | 2951 |
| 2901 __ IncrementCounter(&Counters::keyed_load_string_length, 1); | 2952 __ IncrementCounter(&Counters::keyed_load_string_length, 1); |
| 2902 | 2953 |
| 2903 // Check that the name has not changed. | 2954 // Check that the name has not changed. |
| 2904 __ Cmp(rax, Handle<String>(name)); | 2955 __ Cmp(rax, Handle<String>(name)); |
| 2905 __ j(not_equal, &miss); | 2956 __ j(not_equal, &miss); |
| 2906 | 2957 |
| 2907 GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss); | 2958 GenerateLoadStringLength(masm(), rdx, rcx, rbx, &miss, true); |
| 2908 __ bind(&miss); | 2959 __ bind(&miss); |
| 2909 __ DecrementCounter(&Counters::keyed_load_string_length, 1); | 2960 __ DecrementCounter(&Counters::keyed_load_string_length, 1); |
| 2910 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 2961 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 2911 | 2962 |
| 2912 // Return the generated code. | 2963 // Return the generated code. |
| 2913 return GetCode(CALLBACKS, name); | 2964 return GetCode(CALLBACKS, name); |
| 2914 } | 2965 } |
| 2915 | 2966 |
| 2916 | 2967 |
| 2917 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { | 2968 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2977 __ ret(0); | 3028 __ ret(0); |
| 2978 | 3029 |
| 2979 __ bind(&miss); | 3030 __ bind(&miss); |
| 2980 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3031 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 2981 | 3032 |
| 2982 // Return the generated code. | 3033 // Return the generated code. |
| 2983 return GetCode(NORMAL, NULL); | 3034 return GetCode(NORMAL, NULL); |
| 2984 } | 3035 } |
| 2985 | 3036 |
| 2986 | 3037 |
| 3038 MaybeObject* KeyedLoadStubCompiler::CompileLoadPixelArray(JSObject* receiver) { |
| 3039 // ----------- S t a t e ------------- |
| 3040 // -- rax : key |
| 3041 // -- rdx : receiver |
| 3042 // -- esp[0] : return address |
| 3043 // ----------------------------------- |
| 3044 Label miss; |
| 3045 |
| 3046 // Check that the map matches. |
| 3047 __ CheckMap(rdx, Handle<Map>(receiver->map()), &miss, false); |
| 3048 |
| 3049 GenerateFastPixelArrayLoad(masm(), |
| 3050 rdx, |
| 3051 rax, |
| 3052 rbx, |
| 3053 rcx, |
| 3054 rax, |
| 3055 &miss, |
| 3056 &miss, |
| 3057 &miss); |
| 3058 |
| 3059 __ bind(&miss); |
| 3060 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3061 |
| 3062 // Return the generated code. |
| 3063 return GetCode(NORMAL, NULL); |
| 3064 } |
| 3065 |
| 3066 |
| 2987 // Specialized stub for constructing objects from functions which only have only | 3067 // Specialized stub for constructing objects from functions which only have only |
| 2988 // simple assignments of the form this.x = ...; in their body. | 3068 // simple assignments of the form this.x = ...; in their body. |
| 2989 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { | 3069 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { |
| 2990 // ----------- S t a t e ------------- | 3070 // ----------- S t a t e ------------- |
| 2991 // -- rax : argc | 3071 // -- rax : argc |
| 2992 // -- rdi : constructor | 3072 // -- rdi : constructor |
| 2993 // -- rsp[0] : return address | 3073 // -- rsp[0] : return address |
| 2994 // -- rsp[4] : last argument | 3074 // -- rsp[4] : last argument |
| 2995 // ----------------------------------- | 3075 // ----------------------------------- |
| 2996 Label generic_stub_call; | 3076 Label generic_stub_call; |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3108 __ bind(&generic_stub_call); | 3188 __ bind(&generic_stub_call); |
| 3109 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); | 3189 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); |
| 3110 Handle<Code> generic_construct_stub(code); | 3190 Handle<Code> generic_construct_stub(code); |
| 3111 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); | 3191 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); |
| 3112 | 3192 |
| 3113 // Return the generated code. | 3193 // Return the generated code. |
| 3114 return GetCode(); | 3194 return GetCode(); |
| 3115 } | 3195 } |
| 3116 | 3196 |
| 3117 | 3197 |
| 3198 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( |
| 3199 ExternalArrayType array_type, Code::Flags flags) { |
| 3200 // ----------- S t a t e ------------- |
| 3201 // -- rax : key |
| 3202 // -- rdx : receiver |
| 3203 // -- rsp[0] : return address |
| 3204 // ----------------------------------- |
| 3205 Label slow; |
| 3206 |
| 3207 // Check that the object isn't a smi. |
| 3208 __ JumpIfSmi(rdx, &slow); |
| 3209 |
| 3210 // Check that the key is a smi. |
| 3211 __ JumpIfNotSmi(rax, &slow); |
| 3212 |
| 3213 // Check that the object is a JS object. |
| 3214 __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx); |
| 3215 __ j(not_equal, &slow); |
| 3216 // Check that the receiver does not require access checks. We need |
| 3217 // to check this explicitly since this generic stub does not perform |
| 3218 // map checks. The map is already in rdx. |
| 3219 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), |
| 3220 Immediate(1 << Map::kIsAccessCheckNeeded)); |
| 3221 __ j(not_zero, &slow); |
| 3222 |
| 3223 // Check that the elements array is the appropriate type of |
| 3224 // ExternalArray. |
| 3225 // rax: index (as a smi) |
| 3226 // rdx: JSObject |
| 3227 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 3228 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
| 3229 Heap::RootIndexForExternalArrayType(array_type)); |
| 3230 __ j(not_equal, &slow); |
| 3231 |
| 3232 // Check that the index is in range. |
| 3233 __ SmiToInteger32(rcx, rax); |
| 3234 __ cmpl(rcx, FieldOperand(rbx, ExternalArray::kLengthOffset)); |
| 3235 // Unsigned comparison catches both negative and too-large values. |
| 3236 __ j(above_equal, &slow); |
| 3237 |
| 3238 // rax: index (as a smi) |
| 3239 // rdx: receiver (JSObject) |
| 3240 // rcx: untagged index |
| 3241 // rbx: elements array |
| 3242 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); |
| 3243 // rbx: base pointer of external storage |
| 3244 switch (array_type) { |
| 3245 case kExternalByteArray: |
| 3246 __ movsxbq(rcx, Operand(rbx, rcx, times_1, 0)); |
| 3247 break; |
| 3248 case kExternalUnsignedByteArray: |
| 3249 __ movzxbq(rcx, Operand(rbx, rcx, times_1, 0)); |
| 3250 break; |
| 3251 case kExternalShortArray: |
| 3252 __ movsxwq(rcx, Operand(rbx, rcx, times_2, 0)); |
| 3253 break; |
| 3254 case kExternalUnsignedShortArray: |
| 3255 __ movzxwq(rcx, Operand(rbx, rcx, times_2, 0)); |
| 3256 break; |
| 3257 case kExternalIntArray: |
| 3258 __ movsxlq(rcx, Operand(rbx, rcx, times_4, 0)); |
| 3259 break; |
| 3260 case kExternalUnsignedIntArray: |
| 3261 __ movl(rcx, Operand(rbx, rcx, times_4, 0)); |
| 3262 break; |
| 3263 case kExternalFloatArray: |
| 3264 __ cvtss2sd(xmm0, Operand(rbx, rcx, times_4, 0)); |
| 3265 break; |
| 3266 default: |
| 3267 UNREACHABLE(); |
| 3268 break; |
| 3269 } |
| 3270 |
| 3271 // rax: index |
| 3272 // rdx: receiver |
| 3273 // For integer array types: |
| 3274 // rcx: value |
| 3275 // For floating-point array type: |
| 3276 // xmm0: value as double. |
| 3277 |
| 3278 ASSERT(kSmiValueSize == 32); |
| 3279 if (array_type == kExternalUnsignedIntArray) { |
| 3280 // For the UnsignedInt array type, we need to see whether |
| 3281 // the value can be represented in a Smi. If not, we need to convert |
| 3282 // it to a HeapNumber. |
| 3283 NearLabel box_int; |
| 3284 |
| 3285 __ JumpIfUIntNotValidSmiValue(rcx, &box_int); |
| 3286 |
| 3287 __ Integer32ToSmi(rax, rcx); |
| 3288 __ ret(0); |
| 3289 |
| 3290 __ bind(&box_int); |
| 3291 |
| 3292 // Allocate a HeapNumber for the int and perform int-to-double |
| 3293 // conversion. |
| 3294 // The value is zero-extended since we loaded the value from memory |
| 3295 // with movl. |
| 3296 __ cvtqsi2sd(xmm0, rcx); |
| 3297 |
| 3298 __ AllocateHeapNumber(rcx, rbx, &slow); |
| 3299 // Set the value. |
| 3300 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0); |
| 3301 __ movq(rax, rcx); |
| 3302 __ ret(0); |
| 3303 } else if (array_type == kExternalFloatArray) { |
| 3304 // For the floating-point array type, we need to always allocate a |
| 3305 // HeapNumber. |
| 3306 __ AllocateHeapNumber(rcx, rbx, &slow); |
| 3307 // Set the value. |
| 3308 __ movsd(FieldOperand(rcx, HeapNumber::kValueOffset), xmm0); |
| 3309 __ movq(rax, rcx); |
| 3310 __ ret(0); |
| 3311 } else { |
| 3312 __ Integer32ToSmi(rax, rcx); |
| 3313 __ ret(0); |
| 3314 } |
| 3315 |
| 3316 // Slow case: Jump to runtime. |
| 3317 __ bind(&slow); |
| 3318 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1); |
| 3319 |
| 3320 // ----------- S t a t e ------------- |
| 3321 // -- rax : key |
| 3322 // -- rdx : receiver |
| 3323 // -- rsp[0] : return address |
| 3324 // ----------------------------------- |
| 3325 |
| 3326 __ pop(rbx); |
| 3327 __ push(rdx); // receiver |
| 3328 __ push(rax); // name |
| 3329 __ push(rbx); // return address |
| 3330 |
| 3331 // Perform tail call to the entry. |
| 3332 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
| 3333 |
| 3334 // Return the generated code. |
| 3335 return GetCode(flags); |
| 3336 } |
| 3337 |
| 3338 |
| 3339 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( |
| 3340 ExternalArrayType array_type, Code::Flags flags) { |
| 3341 // ----------- S t a t e ------------- |
| 3342 // -- rax : value |
| 3343 // -- rcx : key |
| 3344 // -- rdx : receiver |
| 3345 // -- rsp[0] : return address |
| 3346 // ----------------------------------- |
| 3347 Label slow; |
| 3348 |
| 3349 // Check that the object isn't a smi. |
| 3350 __ JumpIfSmi(rdx, &slow); |
| 3351 // Get the map from the receiver. |
| 3352 __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 3353 // Check that the receiver does not require access checks. We need |
| 3354 // to do this because this generic stub does not perform map checks. |
| 3355 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 3356 Immediate(1 << Map::kIsAccessCheckNeeded)); |
| 3357 __ j(not_zero, &slow); |
| 3358 // Check that the key is a smi. |
| 3359 __ JumpIfNotSmi(rcx, &slow); |
| 3360 |
| 3361 // Check that the object is a JS object. |
| 3362 __ CmpInstanceType(rbx, JS_OBJECT_TYPE); |
| 3363 __ j(not_equal, &slow); |
| 3364 |
| 3365 // Check that the elements array is the appropriate type of |
| 3366 // ExternalArray. |
| 3367 // rax: value |
| 3368 // rcx: key (a smi) |
| 3369 // rdx: receiver (a JSObject) |
| 3370 __ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset)); |
| 3371 __ CompareRoot(FieldOperand(rbx, HeapObject::kMapOffset), |
| 3372 Heap::RootIndexForExternalArrayType(array_type)); |
| 3373 __ j(not_equal, &slow); |
| 3374 |
| 3375 // Check that the index is in range. |
| 3376 __ SmiToInteger32(rdi, rcx); // Untag the index. |
| 3377 __ cmpl(rdi, FieldOperand(rbx, ExternalArray::kLengthOffset)); |
| 3378 // Unsigned comparison catches both negative and too-large values. |
| 3379 __ j(above_equal, &slow); |
| 3380 |
| 3381 // Handle both smis and HeapNumbers in the fast path. Go to the |
| 3382 // runtime for all other kinds of values. |
| 3383 // rax: value |
| 3384 // rcx: key (a smi) |
| 3385 // rdx: receiver (a JSObject) |
| 3386 // rbx: elements array |
| 3387 // rdi: untagged key |
| 3388 NearLabel check_heap_number; |
| 3389 __ JumpIfNotSmi(rax, &check_heap_number); |
| 3390 // No more branches to slow case on this path. Key and receiver not needed. |
| 3391 __ SmiToInteger32(rdx, rax); |
| 3392 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); |
| 3393 // rbx: base pointer of external storage |
| 3394 switch (array_type) { |
| 3395 case kExternalByteArray: |
| 3396 case kExternalUnsignedByteArray: |
| 3397 __ movb(Operand(rbx, rdi, times_1, 0), rdx); |
| 3398 break; |
| 3399 case kExternalShortArray: |
| 3400 case kExternalUnsignedShortArray: |
| 3401 __ movw(Operand(rbx, rdi, times_2, 0), rdx); |
| 3402 break; |
| 3403 case kExternalIntArray: |
| 3404 case kExternalUnsignedIntArray: |
| 3405 __ movl(Operand(rbx, rdi, times_4, 0), rdx); |
| 3406 break; |
| 3407 case kExternalFloatArray: |
| 3408 // Need to perform int-to-float conversion. |
| 3409 __ cvtlsi2ss(xmm0, rdx); |
| 3410 __ movss(Operand(rbx, rdi, times_4, 0), xmm0); |
| 3411 break; |
| 3412 default: |
| 3413 UNREACHABLE(); |
| 3414 break; |
| 3415 } |
| 3416 __ ret(0); |
| 3417 |
| 3418 __ bind(&check_heap_number); |
| 3419 // rax: value |
| 3420 // rcx: key (a smi) |
| 3421 // rdx: receiver (a JSObject) |
| 3422 // rbx: elements array |
| 3423 // rdi: untagged key |
| 3424 __ CmpObjectType(rax, HEAP_NUMBER_TYPE, kScratchRegister); |
| 3425 __ j(not_equal, &slow); |
| 3426 // No more branches to slow case on this path. |
| 3427 |
| 3428 // The WebGL specification leaves the behavior of storing NaN and |
| 3429 // +/-Infinity into integer arrays basically undefined. For more |
| 3430 // reproducible behavior, convert these to zero. |
| 3431 __ movsd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); |
| 3432 __ movq(rbx, FieldOperand(rbx, ExternalArray::kExternalPointerOffset)); |
| 3433 // rdi: untagged index |
| 3434 // rbx: base pointer of external storage |
| 3435 // top of FPU stack: value |
| 3436 if (array_type == kExternalFloatArray) { |
| 3437 __ cvtsd2ss(xmm0, xmm0); |
| 3438 __ movss(Operand(rbx, rdi, times_4, 0), xmm0); |
| 3439 __ ret(0); |
| 3440 } else { |
| 3441 // Perform float-to-int conversion with truncation (round-to-zero) |
| 3442 // behavior. |
| 3443 |
| 3444 // Convert to int32 and store the low byte/word. |
| 3445 // If the value is NaN or +/-infinity, the result is 0x80000000, |
| 3446 // which is automatically zero when taken mod 2^n, n < 32. |
| 3447 // rdx: value (converted to an untagged integer) |
| 3448 // rdi: untagged index |
| 3449 // rbx: base pointer of external storage |
| 3450 switch (array_type) { |
| 3451 case kExternalByteArray: |
| 3452 case kExternalUnsignedByteArray: |
| 3453 __ cvttsd2si(rdx, xmm0); |
| 3454 __ movb(Operand(rbx, rdi, times_1, 0), rdx); |
| 3455 break; |
| 3456 case kExternalShortArray: |
| 3457 case kExternalUnsignedShortArray: |
| 3458 __ cvttsd2si(rdx, xmm0); |
| 3459 __ movw(Operand(rbx, rdi, times_2, 0), rdx); |
| 3460 break; |
| 3461 case kExternalIntArray: |
| 3462 case kExternalUnsignedIntArray: { |
| 3463 // Convert to int64, so that NaN and infinities become |
| 3464 // 0x8000000000000000, which is zero mod 2^32. |
| 3465 __ cvttsd2siq(rdx, xmm0); |
| 3466 __ movl(Operand(rbx, rdi, times_4, 0), rdx); |
| 3467 break; |
| 3468 } |
| 3469 default: |
| 3470 UNREACHABLE(); |
| 3471 break; |
| 3472 } |
| 3473 __ ret(0); |
| 3474 } |
| 3475 |
| 3476 // Slow case: call runtime. |
| 3477 __ bind(&slow); |
| 3478 |
| 3479 // ----------- S t a t e ------------- |
| 3480 // -- rax : value |
| 3481 // -- rcx : key |
| 3482 // -- rdx : receiver |
| 3483 // -- rsp[0] : return address |
| 3484 // ----------------------------------- |
| 3485 |
| 3486 __ pop(rbx); |
| 3487 __ push(rdx); // receiver |
| 3488 __ push(rcx); // key |
| 3489 __ push(rax); // value |
| 3490 __ push(rbx); // return address |
| 3491 |
| 3492 // Do tail-call to runtime routine. |
| 3493 __ TailCallRuntime(Runtime::kSetProperty, 3, 1); |
| 3494 |
| 3495 return GetCode(flags); |
| 3496 } |
| 3497 |
| 3118 #undef __ | 3498 #undef __ |
| 3119 | 3499 |
| 3120 } } // namespace v8::internal | 3500 } } // namespace v8::internal |
| 3121 | 3501 |
| 3122 #endif // V8_TARGET_ARCH_X64 | 3502 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |