| 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 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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(®ular_invoke); | 661 __ bind(®ular_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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |