| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 ASSERT(kNotStringTag != 0); | 320 ASSERT(kNotStringTag != 0); |
| 321 __ test(scratch, Immediate(kNotStringTag)); | 321 __ test(scratch, Immediate(kNotStringTag)); |
| 322 __ j(not_zero, non_string_object, not_taken); | 322 __ j(not_zero, non_string_object, not_taken); |
| 323 } | 323 } |
| 324 | 324 |
| 325 | 325 |
| 326 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, | 326 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, |
| 327 Register receiver, | 327 Register receiver, |
| 328 Register scratch1, | 328 Register scratch1, |
| 329 Register scratch2, | 329 Register scratch2, |
| 330 Label* miss) { | 330 Label* miss, |
| 331 bool support_wrappers) { |
| 331 Label check_wrapper; | 332 Label check_wrapper; |
| 332 | 333 |
| 333 // Check if the object is a string leaving the instance type in the | 334 // Check if the object is a string leaving the instance type in the |
| 334 // scratch register. | 335 // scratch register. |
| 335 GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper); | 336 GenerateStringCheck(masm, receiver, scratch1, miss, |
| 337 support_wrappers ? &check_wrapper : miss); |
| 336 | 338 |
| 337 // Load length from the string and convert to a smi. | 339 // Load length from the string and convert to a smi. |
| 338 __ mov(eax, FieldOperand(receiver, String::kLengthOffset)); | 340 __ mov(eax, FieldOperand(receiver, String::kLengthOffset)); |
| 339 __ ret(0); | 341 __ ret(0); |
| 340 | 342 |
| 341 // Check if the object is a JSValue wrapper. | 343 if (support_wrappers) { |
| 342 __ bind(&check_wrapper); | 344 // Check if the object is a JSValue wrapper. |
| 343 __ cmp(scratch1, JS_VALUE_TYPE); | 345 __ bind(&check_wrapper); |
| 344 __ j(not_equal, miss, not_taken); | 346 __ cmp(scratch1, JS_VALUE_TYPE); |
| 347 __ j(not_equal, miss, not_taken); |
| 345 | 348 |
| 346 // Check if the wrapped value is a string and load the length | 349 // Check if the wrapped value is a string and load the length |
| 347 // directly if it is. | 350 // directly if it is. |
| 348 __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); | 351 __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); |
| 349 GenerateStringCheck(masm, scratch2, scratch1, miss, miss); | 352 GenerateStringCheck(masm, scratch2, scratch1, miss, miss); |
| 350 __ mov(eax, FieldOperand(scratch2, String::kLengthOffset)); | 353 __ mov(eax, FieldOperand(scratch2, String::kLengthOffset)); |
| 351 __ ret(0); | 354 __ ret(0); |
| 355 } |
| 352 } | 356 } |
| 353 | 357 |
| 354 | 358 |
| 355 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, | 359 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, |
| 356 Register receiver, | 360 Register receiver, |
| 357 Register scratch1, | 361 Register scratch1, |
| 358 Register scratch2, | 362 Register scratch2, |
| 359 Label* miss_label) { | 363 Label* miss_label) { |
| 360 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); | 364 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); |
| 361 __ mov(eax, Operand(scratch1)); | 365 __ mov(eax, Operand(scratch1)); |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal | 448 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal |
| 445 // frame. | 449 // frame. |
| 446 // ----------------------------------- | 450 // ----------------------------------- |
| 447 __ pop(scratch); | 451 __ pop(scratch); |
| 448 __ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments)); | 452 __ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments)); |
| 449 __ push(scratch); | 453 __ push(scratch); |
| 450 } | 454 } |
| 451 | 455 |
| 452 | 456 |
| 453 // Generates call to API function. | 457 // Generates call to API function. |
| 454 static bool GenerateFastApiCall(MacroAssembler* masm, | 458 static MaybeObject* GenerateFastApiCall(MacroAssembler* masm, |
| 455 const CallOptimization& optimization, | 459 const CallOptimization& optimization, |
| 456 int argc, | 460 int argc) { |
| 457 Failure** failure) { | |
| 458 // ----------- S t a t e ------------- | 461 // ----------- S t a t e ------------- |
| 459 // -- esp[0] : return address | 462 // -- esp[0] : return address |
| 460 // -- esp[4] : object passing the type check | 463 // -- esp[4] : object passing the type check |
| 461 // (last fast api call extra argument, | 464 // (last fast api call extra argument, |
| 462 // set by CheckPrototypes) | 465 // set by CheckPrototypes) |
| 463 // -- esp[8] : api function | 466 // -- esp[8] : api function |
| 464 // (first fast api call extra argument) | 467 // (first fast api call extra argument) |
| 465 // -- esp[12] : api call data | 468 // -- esp[12] : api call data |
| 466 // -- esp[16] : last argument | 469 // -- esp[16] : last argument |
| 467 // -- ... | 470 // -- ... |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 __ Set(ApiParameterOperand(4), Immediate(0)); | 512 __ Set(ApiParameterOperand(4), Immediate(0)); |
| 510 | 513 |
| 511 // v8::InvocationCallback's argument. | 514 // v8::InvocationCallback's argument. |
| 512 __ lea(eax, ApiParameterOperand(1)); | 515 __ lea(eax, ApiParameterOperand(1)); |
| 513 __ mov(ApiParameterOperand(0), eax); | 516 __ mov(ApiParameterOperand(0), eax); |
| 514 | 517 |
| 515 // Emitting a stub call may try to allocate (if the code is not | 518 // Emitting a stub call may try to allocate (if the code is not |
| 516 // already generated). Do not allow the assembler to perform a | 519 // already generated). Do not allow the assembler to perform a |
| 517 // garbage collection but instead return the allocation failure | 520 // garbage collection but instead return the allocation failure |
| 518 // object. | 521 // object. |
| 519 MaybeObject* result = | 522 return masm->TryCallApiFunctionAndReturn(&fun, |
| 520 masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1); | 523 argc + kFastApiCallArguments + 1); |
| 521 if (result->IsFailure()) { | |
| 522 *failure = Failure::cast(result); | |
| 523 return false; | |
| 524 } | |
| 525 return true; | |
| 526 } | 524 } |
| 527 | 525 |
| 528 | 526 |
| 529 class CallInterceptorCompiler BASE_EMBEDDED { | 527 class CallInterceptorCompiler BASE_EMBEDDED { |
| 530 public: | 528 public: |
| 531 CallInterceptorCompiler(StubCompiler* stub_compiler, | 529 CallInterceptorCompiler(StubCompiler* stub_compiler, |
| 532 const ParameterCount& arguments, | 530 const ParameterCount& arguments, |
| 533 Register name) | 531 Register name) |
| 534 : stub_compiler_(stub_compiler), | 532 : stub_compiler_(stub_compiler), |
| 535 arguments_(arguments), | 533 arguments_(arguments), |
| 536 name_(name) {} | 534 name_(name) {} |
| 537 | 535 |
| 538 bool Compile(MacroAssembler* masm, | 536 MaybeObject* Compile(MacroAssembler* masm, |
| 539 JSObject* object, | 537 JSObject* object, |
| 540 JSObject* holder, | 538 JSObject* holder, |
| 541 String* name, | 539 String* name, |
| 542 LookupResult* lookup, | 540 LookupResult* lookup, |
| 543 Register receiver, | 541 Register receiver, |
| 544 Register scratch1, | 542 Register scratch1, |
| 545 Register scratch2, | 543 Register scratch2, |
| 546 Register scratch3, | 544 Register scratch3, |
| 547 Label* miss, | 545 Label* miss) { |
| 548 Failure** failure) { | |
| 549 ASSERT(holder->HasNamedInterceptor()); | 546 ASSERT(holder->HasNamedInterceptor()); |
| 550 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | 547 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 551 | 548 |
| 552 // Check that the receiver isn't a smi. | 549 // Check that the receiver isn't a smi. |
| 553 __ test(receiver, Immediate(kSmiTagMask)); | 550 __ test(receiver, Immediate(kSmiTagMask)); |
| 554 __ j(zero, miss, not_taken); | 551 __ j(zero, miss, not_taken); |
| 555 | 552 |
| 556 CallOptimization optimization(lookup); | 553 CallOptimization optimization(lookup); |
| 557 | 554 |
| 558 if (optimization.is_constant_call()) { | 555 if (optimization.is_constant_call()) { |
| 559 return CompileCacheable(masm, | 556 return CompileCacheable(masm, |
| 560 object, | 557 object, |
| 561 receiver, | 558 receiver, |
| 562 scratch1, | 559 scratch1, |
| 563 scratch2, | 560 scratch2, |
| 564 scratch3, | 561 scratch3, |
| 565 holder, | 562 holder, |
| 566 lookup, | 563 lookup, |
| 567 name, | 564 name, |
| 568 optimization, | 565 optimization, |
| 569 miss, | 566 miss); |
| 570 failure); | |
| 571 } else { | 567 } else { |
| 572 CompileRegular(masm, | 568 CompileRegular(masm, |
| 573 object, | 569 object, |
| 574 receiver, | 570 receiver, |
| 575 scratch1, | 571 scratch1, |
| 576 scratch2, | 572 scratch2, |
| 577 scratch3, | 573 scratch3, |
| 578 name, | 574 name, |
| 579 holder, | 575 holder, |
| 580 miss); | 576 miss); |
| 581 return true; | 577 return Heap::undefined_value(); // Success. |
| 582 } | 578 } |
| 583 } | 579 } |
| 584 | 580 |
| 585 private: | 581 private: |
| 586 bool CompileCacheable(MacroAssembler* masm, | 582 MaybeObject* CompileCacheable(MacroAssembler* masm, |
| 587 JSObject* object, | 583 JSObject* object, |
| 588 Register receiver, | 584 Register receiver, |
| 589 Register scratch1, | 585 Register scratch1, |
| 590 Register scratch2, | 586 Register scratch2, |
| 591 Register scratch3, | 587 Register scratch3, |
| 592 JSObject* interceptor_holder, | 588 JSObject* interceptor_holder, |
| 593 LookupResult* lookup, | 589 LookupResult* lookup, |
| 594 String* name, | 590 String* name, |
| 595 const CallOptimization& optimization, | 591 const CallOptimization& optimization, |
| 596 Label* miss_label, | 592 Label* miss_label) { |
| 597 Failure** failure) { | |
| 598 ASSERT(optimization.is_constant_call()); | 593 ASSERT(optimization.is_constant_call()); |
| 599 ASSERT(!lookup->holder()->IsGlobalObject()); | 594 ASSERT(!lookup->holder()->IsGlobalObject()); |
| 600 | 595 |
| 601 int depth1 = kInvalidProtoDepth; | 596 int depth1 = kInvalidProtoDepth; |
| 602 int depth2 = kInvalidProtoDepth; | 597 int depth2 = kInvalidProtoDepth; |
| 603 bool can_do_fast_api_call = false; | 598 bool can_do_fast_api_call = false; |
| 604 if (optimization.is_simple_api_call() && | 599 if (optimization.is_simple_api_call() && |
| 605 !lookup->holder()->IsGlobalObject()) { | 600 !lookup->holder()->IsGlobalObject()) { |
| 606 depth1 = | 601 depth1 = |
| 607 optimization.GetPrototypeDepthOfExpectedType(object, | 602 optimization.GetPrototypeDepthOfExpectedType(object, |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 649 } else { | 644 } else { |
| 650 // CheckPrototypes has a side effect of fetching a 'holder' | 645 // CheckPrototypes has a side effect of fetching a 'holder' |
| 651 // for API (object which is instanceof for the signature). It's | 646 // for API (object which is instanceof for the signature). It's |
| 652 // safe to omit it here, as if present, it should be fetched | 647 // safe to omit it here, as if present, it should be fetched |
| 653 // by the previous CheckPrototypes. | 648 // by the previous CheckPrototypes. |
| 654 ASSERT(depth2 == kInvalidProtoDepth); | 649 ASSERT(depth2 == kInvalidProtoDepth); |
| 655 } | 650 } |
| 656 | 651 |
| 657 // Invoke function. | 652 // Invoke function. |
| 658 if (can_do_fast_api_call) { | 653 if (can_do_fast_api_call) { |
| 659 bool success = GenerateFastApiCall(masm, optimization, | 654 MaybeObject* result = |
| 660 arguments_.immediate(), failure); | 655 GenerateFastApiCall(masm, optimization, arguments_.immediate()); |
| 661 if (!success) { | 656 if (result->IsFailure()) return result; |
| 662 return false; | |
| 663 } | |
| 664 } else { | 657 } else { |
| 665 __ InvokeFunction(optimization.constant_function(), arguments_, | 658 __ InvokeFunction(optimization.constant_function(), arguments_, |
| 666 JUMP_FUNCTION); | 659 JUMP_FUNCTION); |
| 667 } | 660 } |
| 668 | 661 |
| 669 // Deferred code for fast API call case---clean preallocated space. | 662 // Deferred code for fast API call case---clean preallocated space. |
| 670 if (can_do_fast_api_call) { | 663 if (can_do_fast_api_call) { |
| 671 __ bind(&miss_cleanup); | 664 __ bind(&miss_cleanup); |
| 672 FreeSpaceForFastApiCall(masm, scratch1); | 665 FreeSpaceForFastApiCall(masm, scratch1); |
| 673 __ jmp(miss_label); | 666 __ jmp(miss_label); |
| 674 } | 667 } |
| 675 | 668 |
| 676 // Invoke a regular function. | 669 // Invoke a regular function. |
| 677 __ bind(®ular_invoke); | 670 __ bind(®ular_invoke); |
| 678 if (can_do_fast_api_call) { | 671 if (can_do_fast_api_call) { |
| 679 FreeSpaceForFastApiCall(masm, scratch1); | 672 FreeSpaceForFastApiCall(masm, scratch1); |
| 680 } | 673 } |
| 681 | 674 |
| 682 return true; | 675 return Heap::undefined_value(); // Success. |
| 683 } | 676 } |
| 684 | 677 |
| 685 void CompileRegular(MacroAssembler* masm, | 678 void CompileRegular(MacroAssembler* masm, |
| 686 JSObject* object, | 679 JSObject* object, |
| 687 Register receiver, | 680 Register receiver, |
| 688 Register scratch1, | 681 Register scratch1, |
| 689 Register scratch2, | 682 Register scratch2, |
| 690 Register scratch3, | 683 Register scratch3, |
| 691 String* name, | 684 String* name, |
| 692 JSObject* interceptor_holder, | 685 JSObject* interceptor_holder, |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1050 Register reg = | 1043 Register reg = |
| 1051 CheckPrototypes(object, receiver, holder, | 1044 CheckPrototypes(object, receiver, holder, |
| 1052 scratch1, scratch2, scratch3, name, miss); | 1045 scratch1, scratch2, scratch3, name, miss); |
| 1053 | 1046 |
| 1054 // Get the value from the properties. | 1047 // Get the value from the properties. |
| 1055 GenerateFastPropertyLoad(masm(), eax, reg, holder, index); | 1048 GenerateFastPropertyLoad(masm(), eax, reg, holder, index); |
| 1056 __ ret(0); | 1049 __ ret(0); |
| 1057 } | 1050 } |
| 1058 | 1051 |
| 1059 | 1052 |
| 1060 bool StubCompiler::GenerateLoadCallback(JSObject* object, | 1053 MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, |
| 1061 JSObject* holder, | 1054 JSObject* holder, |
| 1062 Register receiver, | 1055 Register receiver, |
| 1063 Register name_reg, | 1056 Register name_reg, |
| 1064 Register scratch1, | 1057 Register scratch1, |
| 1065 Register scratch2, | 1058 Register scratch2, |
| 1066 Register scratch3, | 1059 Register scratch3, |
| 1067 AccessorInfo* callback, | 1060 AccessorInfo* callback, |
| 1068 String* name, | 1061 String* name, |
| 1069 Label* miss, | 1062 Label* miss) { |
| 1070 Failure** failure) { | |
| 1071 // Check that the receiver isn't a smi. | 1063 // Check that the receiver isn't a smi. |
| 1072 __ test(receiver, Immediate(kSmiTagMask)); | 1064 __ test(receiver, Immediate(kSmiTagMask)); |
| 1073 __ j(zero, miss, not_taken); | 1065 __ j(zero, miss, not_taken); |
| 1074 | 1066 |
| 1075 // Check that the maps haven't changed. | 1067 // Check that the maps haven't changed. |
| 1076 Register reg = | 1068 Register reg = |
| 1077 CheckPrototypes(object, receiver, holder, scratch1, | 1069 CheckPrototypes(object, receiver, holder, scratch1, |
| 1078 scratch2, scratch3, name, miss); | 1070 scratch2, scratch3, name, miss); |
| 1079 | 1071 |
| 1080 Handle<AccessorInfo> callback_handle(callback); | 1072 Handle<AccessorInfo> callback_handle(callback); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1115 | 1107 |
| 1116 __ PrepareCallApiFunction(kApiArgc, eax); | 1108 __ PrepareCallApiFunction(kApiArgc, eax); |
| 1117 __ mov(ApiParameterOperand(0), ebx); // name. | 1109 __ mov(ApiParameterOperand(0), ebx); // name. |
| 1118 __ add(Operand(ebx), Immediate(kPointerSize)); | 1110 __ add(Operand(ebx), Immediate(kPointerSize)); |
| 1119 __ mov(ApiParameterOperand(1), ebx); // arguments pointer. | 1111 __ mov(ApiParameterOperand(1), ebx); // arguments pointer. |
| 1120 | 1112 |
| 1121 // Emitting a stub call may try to allocate (if the code is not | 1113 // Emitting a stub call may try to allocate (if the code is not |
| 1122 // already generated). Do not allow the assembler to perform a | 1114 // already generated). Do not allow the assembler to perform a |
| 1123 // garbage collection but instead return the allocation failure | 1115 // garbage collection but instead return the allocation failure |
| 1124 // object. | 1116 // object. |
| 1125 MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); | 1117 return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); |
| 1126 if (result->IsFailure()) { | |
| 1127 *failure = Failure::cast(result); | |
| 1128 return false; | |
| 1129 } | |
| 1130 | |
| 1131 return true; | |
| 1132 } | 1118 } |
| 1133 | 1119 |
| 1134 | 1120 |
| 1135 void StubCompiler::GenerateLoadConstant(JSObject* object, | 1121 void StubCompiler::GenerateLoadConstant(JSObject* object, |
| 1136 JSObject* holder, | 1122 JSObject* holder, |
| 1137 Register receiver, | 1123 Register receiver, |
| 1138 Register scratch1, | 1124 Register scratch1, |
| 1139 Register scratch2, | 1125 Register scratch2, |
| 1140 Register scratch3, | 1126 Register scratch3, |
| 1141 Object* value, | 1127 Object* value, |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1355 Immediate(Handle<SharedFunctionInfo>(function->shared()))); | 1341 Immediate(Handle<SharedFunctionInfo>(function->shared()))); |
| 1356 __ j(not_equal, miss, not_taken); | 1342 __ j(not_equal, miss, not_taken); |
| 1357 } else { | 1343 } else { |
| 1358 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function))); | 1344 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function))); |
| 1359 __ j(not_equal, miss, not_taken); | 1345 __ j(not_equal, miss, not_taken); |
| 1360 } | 1346 } |
| 1361 } | 1347 } |
| 1362 | 1348 |
| 1363 | 1349 |
| 1364 MaybeObject* CallStubCompiler::GenerateMissBranch() { | 1350 MaybeObject* CallStubCompiler::GenerateMissBranch() { |
| 1351 MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(), |
| 1352 kind_); |
| 1365 Object* obj; | 1353 Object* obj; |
| 1366 { MaybeObject* maybe_obj = | 1354 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 1367 StubCache::ComputeCallMiss(arguments().immediate(), kind_); | |
| 1368 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | |
| 1369 } | |
| 1370 __ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); | 1355 __ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); |
| 1371 return obj; | 1356 return obj; |
| 1372 } | 1357 } |
| 1373 | 1358 |
| 1374 | 1359 |
| 1375 MUST_USE_RESULT MaybeObject* CallStubCompiler::CompileCallField( | 1360 MUST_USE_RESULT MaybeObject* CallStubCompiler::CompileCallField( |
| 1376 JSObject* object, | 1361 JSObject* object, |
| 1377 JSObject* holder, | 1362 JSObject* holder, |
| 1378 int index, | 1363 int index, |
| 1379 String* name) { | 1364 String* name) { |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1679 // -- ... | 1664 // -- ... |
| 1680 // -- esp[(argc + 1) * 4] : receiver | 1665 // -- esp[(argc + 1) * 4] : receiver |
| 1681 // ----------------------------------- | 1666 // ----------------------------------- |
| 1682 | 1667 |
| 1683 // If object is not a string, bail out to regular call. | 1668 // If object is not a string, bail out to regular call. |
| 1684 if (!object->IsString() || cell != NULL) return Heap::undefined_value(); | 1669 if (!object->IsString() || cell != NULL) return Heap::undefined_value(); |
| 1685 | 1670 |
| 1686 const int argc = arguments().immediate(); | 1671 const int argc = arguments().immediate(); |
| 1687 | 1672 |
| 1688 Label miss; | 1673 Label miss; |
| 1674 Label name_miss; |
| 1689 Label index_out_of_range; | 1675 Label index_out_of_range; |
| 1676 Label* index_out_of_range_label = &index_out_of_range; |
| 1690 | 1677 |
| 1691 GenerateNameCheck(name, &miss); | 1678 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { |
| 1679 index_out_of_range_label = &miss; |
| 1680 } |
| 1681 |
| 1682 GenerateNameCheck(name, &name_miss); |
| 1692 | 1683 |
| 1693 // Check that the maps starting from the prototype haven't changed. | 1684 // Check that the maps starting from the prototype haven't changed. |
| 1694 GenerateDirectLoadGlobalFunctionPrototype(masm(), | 1685 GenerateDirectLoadGlobalFunctionPrototype(masm(), |
| 1695 Context::STRING_FUNCTION_INDEX, | 1686 Context::STRING_FUNCTION_INDEX, |
| 1696 eax, | 1687 eax, |
| 1697 &miss); | 1688 &miss); |
| 1698 ASSERT(object != holder); | 1689 ASSERT(object != holder); |
| 1699 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 1690 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
| 1700 ebx, edx, edi, name, &miss); | 1691 ebx, edx, edi, name, &miss); |
| 1701 | 1692 |
| 1702 Register receiver = ebx; | 1693 Register receiver = ebx; |
| 1703 Register index = edi; | 1694 Register index = edi; |
| 1704 Register scratch = edx; | 1695 Register scratch = edx; |
| 1705 Register result = eax; | 1696 Register result = eax; |
| 1706 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); | 1697 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); |
| 1707 if (argc > 0) { | 1698 if (argc > 0) { |
| 1708 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); | 1699 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); |
| 1709 } else { | 1700 } else { |
| 1710 __ Set(index, Immediate(Factory::undefined_value())); | 1701 __ Set(index, Immediate(Factory::undefined_value())); |
| 1711 } | 1702 } |
| 1712 | 1703 |
| 1713 StringCharCodeAtGenerator char_code_at_generator(receiver, | 1704 StringCharCodeAtGenerator char_code_at_generator(receiver, |
| 1714 index, | 1705 index, |
| 1715 scratch, | 1706 scratch, |
| 1716 result, | 1707 result, |
| 1717 &miss, // When not a string. | 1708 &miss, // When not a string. |
| 1718 &miss, // When not a number. | 1709 &miss, // When not a number. |
| 1719 &index_out_of_range, | 1710 index_out_of_range_label, |
| 1720 STRING_INDEX_IS_NUMBER); | 1711 STRING_INDEX_IS_NUMBER); |
| 1721 char_code_at_generator.GenerateFast(masm()); | 1712 char_code_at_generator.GenerateFast(masm()); |
| 1722 __ ret((argc + 1) * kPointerSize); | 1713 __ ret((argc + 1) * kPointerSize); |
| 1723 | 1714 |
| 1724 StubRuntimeCallHelper call_helper; | 1715 StubRuntimeCallHelper call_helper; |
| 1725 char_code_at_generator.GenerateSlow(masm(), call_helper); | 1716 char_code_at_generator.GenerateSlow(masm(), call_helper); |
| 1726 | 1717 |
| 1727 __ bind(&index_out_of_range); | 1718 if (index_out_of_range.is_linked()) { |
| 1728 __ Set(eax, Immediate(Factory::nan_value())); | 1719 __ bind(&index_out_of_range); |
| 1729 __ ret((argc + 1) * kPointerSize); | 1720 __ Set(eax, Immediate(Factory::nan_value())); |
| 1721 __ ret((argc + 1) * kPointerSize); |
| 1722 } |
| 1730 | 1723 |
| 1731 __ bind(&miss); | 1724 __ bind(&miss); |
| 1725 // Restore function name in ecx. |
| 1726 __ Set(ecx, Immediate(Handle<String>(name))); |
| 1727 __ bind(&name_miss); |
| 1732 Object* obj; | 1728 Object* obj; |
| 1733 { MaybeObject* maybe_obj = GenerateMissBranch(); | 1729 { MaybeObject* maybe_obj = GenerateMissBranch(); |
| 1734 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1730 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 1735 } | 1731 } |
| 1736 | 1732 |
| 1737 // Return the generated code. | 1733 // Return the generated code. |
| 1738 return GetCode(function); | 1734 return GetCode(function); |
| 1739 } | 1735 } |
| 1740 | 1736 |
| 1741 | 1737 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1752 // -- ... | 1748 // -- ... |
| 1753 // -- esp[(argc + 1) * 4] : receiver | 1749 // -- esp[(argc + 1) * 4] : receiver |
| 1754 // ----------------------------------- | 1750 // ----------------------------------- |
| 1755 | 1751 |
| 1756 // If object is not a string, bail out to regular call. | 1752 // If object is not a string, bail out to regular call. |
| 1757 if (!object->IsString() || cell != NULL) return Heap::undefined_value(); | 1753 if (!object->IsString() || cell != NULL) return Heap::undefined_value(); |
| 1758 | 1754 |
| 1759 const int argc = arguments().immediate(); | 1755 const int argc = arguments().immediate(); |
| 1760 | 1756 |
| 1761 Label miss; | 1757 Label miss; |
| 1758 Label name_miss; |
| 1762 Label index_out_of_range; | 1759 Label index_out_of_range; |
| 1760 Label* index_out_of_range_label = &index_out_of_range; |
| 1763 | 1761 |
| 1764 GenerateNameCheck(name, &miss); | 1762 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { |
| 1763 index_out_of_range_label = &miss; |
| 1764 } |
| 1765 |
| 1766 GenerateNameCheck(name, &name_miss); |
| 1765 | 1767 |
| 1766 // Check that the maps starting from the prototype haven't changed. | 1768 // Check that the maps starting from the prototype haven't changed. |
| 1767 GenerateDirectLoadGlobalFunctionPrototype(masm(), | 1769 GenerateDirectLoadGlobalFunctionPrototype(masm(), |
| 1768 Context::STRING_FUNCTION_INDEX, | 1770 Context::STRING_FUNCTION_INDEX, |
| 1769 eax, | 1771 eax, |
| 1770 &miss); | 1772 &miss); |
| 1771 ASSERT(object != holder); | 1773 ASSERT(object != holder); |
| 1772 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 1774 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
| 1773 ebx, edx, edi, name, &miss); | 1775 ebx, edx, edi, name, &miss); |
| 1774 | 1776 |
| 1775 Register receiver = eax; | 1777 Register receiver = eax; |
| 1776 Register index = edi; | 1778 Register index = edi; |
| 1777 Register scratch1 = ebx; | 1779 Register scratch1 = ebx; |
| 1778 Register scratch2 = edx; | 1780 Register scratch2 = edx; |
| 1779 Register result = eax; | 1781 Register result = eax; |
| 1780 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); | 1782 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); |
| 1781 if (argc > 0) { | 1783 if (argc > 0) { |
| 1782 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); | 1784 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); |
| 1783 } else { | 1785 } else { |
| 1784 __ Set(index, Immediate(Factory::undefined_value())); | 1786 __ Set(index, Immediate(Factory::undefined_value())); |
| 1785 } | 1787 } |
| 1786 | 1788 |
| 1787 StringCharAtGenerator char_at_generator(receiver, | 1789 StringCharAtGenerator char_at_generator(receiver, |
| 1788 index, | 1790 index, |
| 1789 scratch1, | 1791 scratch1, |
| 1790 scratch2, | 1792 scratch2, |
| 1791 result, | 1793 result, |
| 1792 &miss, // When not a string. | 1794 &miss, // When not a string. |
| 1793 &miss, // When not a number. | 1795 &miss, // When not a number. |
| 1794 &index_out_of_range, | 1796 index_out_of_range_label, |
| 1795 STRING_INDEX_IS_NUMBER); | 1797 STRING_INDEX_IS_NUMBER); |
| 1796 char_at_generator.GenerateFast(masm()); | 1798 char_at_generator.GenerateFast(masm()); |
| 1797 __ ret((argc + 1) * kPointerSize); | 1799 __ ret((argc + 1) * kPointerSize); |
| 1798 | 1800 |
| 1799 StubRuntimeCallHelper call_helper; | 1801 StubRuntimeCallHelper call_helper; |
| 1800 char_at_generator.GenerateSlow(masm(), call_helper); | 1802 char_at_generator.GenerateSlow(masm(), call_helper); |
| 1801 | 1803 |
| 1802 __ bind(&index_out_of_range); | 1804 if (index_out_of_range.is_linked()) { |
| 1803 __ Set(eax, Immediate(Factory::empty_string())); | 1805 __ bind(&index_out_of_range); |
| 1804 __ ret((argc + 1) * kPointerSize); | 1806 __ Set(eax, Immediate(Factory::empty_string())); |
| 1807 __ ret((argc + 1) * kPointerSize); |
| 1808 } |
| 1805 | 1809 |
| 1806 __ bind(&miss); | 1810 __ bind(&miss); |
| 1811 // Restore function name in ecx. |
| 1812 __ Set(ecx, Immediate(Handle<String>(name))); |
| 1813 __ bind(&name_miss); |
| 1807 Object* obj; | 1814 Object* obj; |
| 1808 { MaybeObject* maybe_obj = GenerateMissBranch(); | 1815 { MaybeObject* maybe_obj = GenerateMissBranch(); |
| 1809 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1816 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 1810 } | 1817 } |
| 1811 | 1818 |
| 1812 // Return the generated code. | 1819 // Return the generated code. |
| 1813 return GetCode(function); | 1820 return GetCode(function); |
| 1814 } | 1821 } |
| 1815 | 1822 |
| 1816 | 1823 |
| (...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2253 ebx, edx, edi, name, &miss); | 2260 ebx, edx, edi, name, &miss); |
| 2254 } | 2261 } |
| 2255 break; | 2262 break; |
| 2256 } | 2263 } |
| 2257 | 2264 |
| 2258 default: | 2265 default: |
| 2259 UNREACHABLE(); | 2266 UNREACHABLE(); |
| 2260 } | 2267 } |
| 2261 | 2268 |
| 2262 if (depth != kInvalidProtoDepth) { | 2269 if (depth != kInvalidProtoDepth) { |
| 2263 Failure* failure; | |
| 2264 // Move the return address on top of the stack. | 2270 // Move the return address on top of the stack. |
| 2265 __ mov(eax, Operand(esp, 3 * kPointerSize)); | 2271 __ mov(eax, Operand(esp, 3 * kPointerSize)); |
| 2266 __ mov(Operand(esp, 0 * kPointerSize), eax); | 2272 __ mov(Operand(esp, 0 * kPointerSize), eax); |
| 2267 | 2273 |
| 2268 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains | 2274 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains |
| 2269 // duplicate of return address and will be overwritten. | 2275 // duplicate of return address and will be overwritten. |
| 2270 bool success = GenerateFastApiCall(masm(), optimization, argc, &failure); | 2276 MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc); |
| 2271 if (!success) { | 2277 if (result->IsFailure()) return result; |
| 2272 return failure; | |
| 2273 } | |
| 2274 } else { | 2278 } else { |
| 2275 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); | 2279 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); |
| 2276 } | 2280 } |
| 2277 | 2281 |
| 2278 // Handle call cache miss. | 2282 // Handle call cache miss. |
| 2279 __ bind(&miss); | 2283 __ bind(&miss); |
| 2280 if (depth != kInvalidProtoDepth) { | 2284 if (depth != kInvalidProtoDepth) { |
| 2281 __ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); | 2285 __ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); |
| 2282 } | 2286 } |
| 2283 __ bind(&miss_in_smi_check); | 2287 __ bind(&miss_in_smi_check); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2308 // Get the number of arguments. | 2312 // Get the number of arguments. |
| 2309 const int argc = arguments().immediate(); | 2313 const int argc = arguments().immediate(); |
| 2310 | 2314 |
| 2311 LookupResult lookup; | 2315 LookupResult lookup; |
| 2312 LookupPostInterceptor(holder, name, &lookup); | 2316 LookupPostInterceptor(holder, name, &lookup); |
| 2313 | 2317 |
| 2314 // Get the receiver from the stack. | 2318 // Get the receiver from the stack. |
| 2315 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2319 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2316 | 2320 |
| 2317 CallInterceptorCompiler compiler(this, arguments(), ecx); | 2321 CallInterceptorCompiler compiler(this, arguments(), ecx); |
| 2318 Failure* failure; | 2322 MaybeObject* result = compiler.Compile(masm(), |
| 2319 bool success = compiler.Compile(masm(), | 2323 object, |
| 2320 object, | 2324 holder, |
| 2321 holder, | 2325 name, |
| 2322 name, | 2326 &lookup, |
| 2323 &lookup, | 2327 edx, |
| 2324 edx, | 2328 ebx, |
| 2325 ebx, | 2329 edi, |
| 2326 edi, | 2330 eax, |
| 2327 eax, | 2331 &miss); |
| 2328 &miss, | 2332 if (result->IsFailure()) return result; |
| 2329 &failure); | |
| 2330 if (!success) { | |
| 2331 return failure; | |
| 2332 } | |
| 2333 | 2333 |
| 2334 // Restore receiver. | 2334 // Restore receiver. |
| 2335 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2335 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2336 | 2336 |
| 2337 // Check that the function really is a function. | 2337 // Check that the function really is a function. |
| 2338 __ test(eax, Immediate(kSmiTagMask)); | 2338 __ test(eax, Immediate(kSmiTagMask)); |
| 2339 __ j(zero, &miss, not_taken); | 2339 __ j(zero, &miss, not_taken); |
| 2340 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); | 2340 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
| 2341 __ j(not_equal, &miss, not_taken); | 2341 __ j(not_equal, &miss, not_taken); |
| 2342 | 2342 |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2576 // -- edx : receiver | 2576 // -- edx : receiver |
| 2577 // -- esp[0] : return address | 2577 // -- esp[0] : return address |
| 2578 // ----------------------------------- | 2578 // ----------------------------------- |
| 2579 Label miss; | 2579 Label miss; |
| 2580 | 2580 |
| 2581 // Check that the map of the global has not changed. | 2581 // Check that the map of the global has not changed. |
| 2582 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 2582 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 2583 Immediate(Handle<Map>(object->map()))); | 2583 Immediate(Handle<Map>(object->map()))); |
| 2584 __ j(not_equal, &miss, not_taken); | 2584 __ j(not_equal, &miss, not_taken); |
| 2585 | 2585 |
| 2586 // Store the value in the cell. | 2586 |
| 2587 // Compute the cell operand to use. |
| 2588 Operand cell_operand = Operand::Cell(Handle<JSGlobalPropertyCell>(cell)); |
| 2587 if (Serializer::enabled()) { | 2589 if (Serializer::enabled()) { |
| 2588 __ mov(ecx, Immediate(Handle<JSGlobalPropertyCell>(cell))); | 2590 __ mov(ecx, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
| 2589 __ mov(FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset), eax); | 2591 cell_operand = FieldOperand(ecx, JSGlobalPropertyCell::kValueOffset); |
| 2590 } else { | |
| 2591 __ mov(Operand::Cell(Handle<JSGlobalPropertyCell>(cell)), eax); | |
| 2592 } | 2592 } |
| 2593 | 2593 |
| 2594 // Check that the value in the cell is not the hole. If it is, this |
| 2595 // cell could have been deleted and reintroducing the global needs |
| 2596 // to update the property details in the property dictionary of the |
| 2597 // global object. We bail out to the runtime system to do that. |
| 2598 __ cmp(cell_operand, Factory::the_hole_value()); |
| 2599 __ j(equal, &miss); |
| 2600 |
| 2601 // Store the value in the cell. |
| 2602 __ mov(cell_operand, eax); |
| 2603 |
| 2594 // Return the value (register eax). | 2604 // Return the value (register eax). |
| 2595 __ IncrementCounter(&Counters::named_store_global_inline, 1); | 2605 __ IncrementCounter(&Counters::named_store_global_inline, 1); |
| 2596 __ ret(0); | 2606 __ ret(0); |
| 2597 | 2607 |
| 2598 // Handle store cache miss. | 2608 // Handle store cache miss. |
| 2599 __ bind(&miss); | 2609 __ bind(&miss); |
| 2600 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1); | 2610 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1); |
| 2601 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 2611 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); |
| 2602 __ jmp(ic, RelocInfo::CODE_TARGET); | 2612 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2603 | 2613 |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2693 // Handle store cache miss. | 2703 // Handle store cache miss. |
| 2694 __ bind(&miss); | 2704 __ bind(&miss); |
| 2695 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); | 2705 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); |
| 2696 __ jmp(ic, RelocInfo::CODE_TARGET); | 2706 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2697 | 2707 |
| 2698 // Return the generated code. | 2708 // Return the generated code. |
| 2699 return GetCode(NORMAL, NULL); | 2709 return GetCode(NORMAL, NULL); |
| 2700 } | 2710 } |
| 2701 | 2711 |
| 2702 | 2712 |
| 2713 MaybeObject* KeyedStoreStubCompiler::CompileStorePixelArray( |
| 2714 JSObject* receiver) { |
| 2715 // ----------- S t a t e ------------- |
| 2716 // -- eax : value |
| 2717 // -- ecx : key |
| 2718 // -- edx : receiver |
| 2719 // -- esp[0] : return address |
| 2720 // ----------------------------------- |
| 2721 Label miss; |
| 2722 |
| 2723 // Check that the map matches. |
| 2724 __ CheckMap(edx, Handle<Map>(receiver->map()), &miss, false); |
| 2725 |
| 2726 // Do the load. |
| 2727 GenerateFastPixelArrayStore(masm(), |
| 2728 edx, |
| 2729 ecx, |
| 2730 eax, |
| 2731 edi, |
| 2732 ebx, |
| 2733 true, |
| 2734 &miss, |
| 2735 &miss, |
| 2736 NULL, |
| 2737 &miss); |
| 2738 |
| 2739 // Handle store cache miss. |
| 2740 __ bind(&miss); |
| 2741 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); |
| 2742 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2743 |
| 2744 // Return the generated code. |
| 2745 return GetCode(NORMAL, NULL); |
| 2746 } |
| 2747 |
| 2748 |
| 2703 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, | 2749 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, |
| 2704 JSObject* object, | 2750 JSObject* object, |
| 2705 JSObject* last) { | 2751 JSObject* last) { |
| 2706 // ----------- S t a t e ------------- | 2752 // ----------- S t a t e ------------- |
| 2707 // -- eax : receiver | 2753 // -- eax : receiver |
| 2708 // -- ecx : name | 2754 // -- ecx : name |
| 2709 // -- esp[0] : return address | 2755 // -- esp[0] : return address |
| 2710 // ----------------------------------- | 2756 // ----------------------------------- |
| 2711 Label miss; | 2757 Label miss; |
| 2712 | 2758 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2772 JSObject* object, | 2818 JSObject* object, |
| 2773 JSObject* holder, | 2819 JSObject* holder, |
| 2774 AccessorInfo* callback) { | 2820 AccessorInfo* callback) { |
| 2775 // ----------- S t a t e ------------- | 2821 // ----------- S t a t e ------------- |
| 2776 // -- eax : receiver | 2822 // -- eax : receiver |
| 2777 // -- ecx : name | 2823 // -- ecx : name |
| 2778 // -- esp[0] : return address | 2824 // -- esp[0] : return address |
| 2779 // ----------------------------------- | 2825 // ----------------------------------- |
| 2780 Label miss; | 2826 Label miss; |
| 2781 | 2827 |
| 2782 Failure* failure = Failure::InternalError(); | 2828 MaybeObject* result = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, |
| 2783 bool success = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, edi, | 2829 edi, callback, name, &miss); |
| 2784 callback, name, &miss, &failure); | 2830 if (result->IsFailure()) { |
| 2785 if (!success) { | |
| 2786 miss.Unuse(); | 2831 miss.Unuse(); |
| 2787 return failure; | 2832 return result; |
| 2788 } | 2833 } |
| 2789 | 2834 |
| 2790 __ bind(&miss); | 2835 __ bind(&miss); |
| 2791 GenerateLoadMiss(masm(), Code::LOAD_IC); | 2836 GenerateLoadMiss(masm(), Code::LOAD_IC); |
| 2792 | 2837 |
| 2793 // Return the generated code. | 2838 // Return the generated code. |
| 2794 return GetCode(CALLBACKS, name); | 2839 return GetCode(CALLBACKS, name); |
| 2795 } | 2840 } |
| 2796 | 2841 |
| 2797 | 2842 |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2941 // -- esp[0] : return address | 2986 // -- esp[0] : return address |
| 2942 // ----------------------------------- | 2987 // ----------------------------------- |
| 2943 Label miss; | 2988 Label miss; |
| 2944 | 2989 |
| 2945 __ IncrementCounter(&Counters::keyed_load_callback, 1); | 2990 __ IncrementCounter(&Counters::keyed_load_callback, 1); |
| 2946 | 2991 |
| 2947 // Check that the name has not changed. | 2992 // Check that the name has not changed. |
| 2948 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 2993 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 2949 __ j(not_equal, &miss, not_taken); | 2994 __ j(not_equal, &miss, not_taken); |
| 2950 | 2995 |
| 2951 Failure* failure = Failure::InternalError(); | 2996 MaybeObject* result = GenerateLoadCallback(receiver, holder, edx, eax, ebx, |
| 2952 bool success = GenerateLoadCallback(receiver, holder, edx, eax, ebx, ecx, edi, | 2997 ecx, edi, callback, name, &miss); |
| 2953 callback, name, &miss, &failure); | 2998 if (result->IsFailure()) { |
| 2954 if (!success) { | |
| 2955 miss.Unuse(); | 2999 miss.Unuse(); |
| 2956 return failure; | 3000 return result; |
| 2957 } | 3001 } |
| 2958 | 3002 |
| 2959 __ bind(&miss); | 3003 __ bind(&miss); |
| 2960 | 3004 |
| 2961 __ DecrementCounter(&Counters::keyed_load_callback, 1); | 3005 __ DecrementCounter(&Counters::keyed_load_callback, 1); |
| 2962 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3006 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 2963 | 3007 |
| 2964 // Return the generated code. | 3008 // Return the generated code. |
| 2965 return GetCode(CALLBACKS, name); | 3009 return GetCode(CALLBACKS, name); |
| 2966 } | 3010 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3062 // -- esp[0] : return address | 3106 // -- esp[0] : return address |
| 3063 // ----------------------------------- | 3107 // ----------------------------------- |
| 3064 Label miss; | 3108 Label miss; |
| 3065 | 3109 |
| 3066 __ IncrementCounter(&Counters::keyed_load_string_length, 1); | 3110 __ IncrementCounter(&Counters::keyed_load_string_length, 1); |
| 3067 | 3111 |
| 3068 // Check that the name has not changed. | 3112 // Check that the name has not changed. |
| 3069 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3113 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3070 __ j(not_equal, &miss, not_taken); | 3114 __ j(not_equal, &miss, not_taken); |
| 3071 | 3115 |
| 3072 GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss); | 3116 GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true); |
| 3073 __ bind(&miss); | 3117 __ bind(&miss); |
| 3074 __ DecrementCounter(&Counters::keyed_load_string_length, 1); | 3118 __ DecrementCounter(&Counters::keyed_load_string_length, 1); |
| 3075 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3119 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3076 | 3120 |
| 3077 // Return the generated code. | 3121 // Return the generated code. |
| 3078 return GetCode(CALLBACKS, name); | 3122 return GetCode(CALLBACKS, name); |
| 3079 } | 3123 } |
| 3080 | 3124 |
| 3081 | 3125 |
| 3082 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { | 3126 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3141 __ ret(0); | 3185 __ ret(0); |
| 3142 | 3186 |
| 3143 __ bind(&miss); | 3187 __ bind(&miss); |
| 3144 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3188 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3145 | 3189 |
| 3146 // Return the generated code. | 3190 // Return the generated code. |
| 3147 return GetCode(NORMAL, NULL); | 3191 return GetCode(NORMAL, NULL); |
| 3148 } | 3192 } |
| 3149 | 3193 |
| 3150 | 3194 |
| 3195 MaybeObject* KeyedLoadStubCompiler::CompileLoadPixelArray(JSObject* receiver) { |
| 3196 // ----------- S t a t e ------------- |
| 3197 // -- eax : key |
| 3198 // -- edx : receiver |
| 3199 // -- esp[0] : return address |
| 3200 // ----------------------------------- |
| 3201 Label miss; |
| 3202 |
| 3203 // Check that the map matches. |
| 3204 __ CheckMap(edx, Handle<Map>(receiver->map()), &miss, false); |
| 3205 |
| 3206 GenerateFastPixelArrayLoad(masm(), |
| 3207 edx, |
| 3208 eax, |
| 3209 ecx, |
| 3210 ebx, |
| 3211 eax, |
| 3212 &miss, |
| 3213 &miss, |
| 3214 &miss); |
| 3215 |
| 3216 // Handle load cache miss. |
| 3217 __ bind(&miss); |
| 3218 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Miss)); |
| 3219 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 3220 |
| 3221 // Return the generated code. |
| 3222 return GetCode(NORMAL, NULL); |
| 3223 } |
| 3224 |
| 3225 |
| 3151 // Specialized stub for constructing objects from functions which only have only | 3226 // Specialized stub for constructing objects from functions which only have only |
| 3152 // simple assignments of the form this.x = ...; in their body. | 3227 // simple assignments of the form this.x = ...; in their body. |
| 3153 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { | 3228 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { |
| 3154 // ----------- S t a t e ------------- | 3229 // ----------- S t a t e ------------- |
| 3155 // -- eax : argc | 3230 // -- eax : argc |
| 3156 // -- edi : constructor | 3231 // -- edi : constructor |
| 3157 // -- esp[0] : return address | 3232 // -- esp[0] : return address |
| 3158 // -- esp[4] : last argument | 3233 // -- esp[4] : last argument |
| 3159 // ----------------------------------- | 3234 // ----------------------------------- |
| 3160 Label generic_stub_call; | 3235 Label generic_stub_call; |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3279 __ bind(&generic_stub_call); | 3354 __ bind(&generic_stub_call); |
| 3280 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); | 3355 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); |
| 3281 Handle<Code> generic_construct_stub(code); | 3356 Handle<Code> generic_construct_stub(code); |
| 3282 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | 3357 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); |
| 3283 | 3358 |
| 3284 // Return the generated code. | 3359 // Return the generated code. |
| 3285 return GetCode(); | 3360 return GetCode(); |
| 3286 } | 3361 } |
| 3287 | 3362 |
| 3288 | 3363 |
| 3364 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( |
| 3365 ExternalArrayType array_type, Code::Flags flags) { |
| 3366 // ----------- S t a t e ------------- |
| 3367 // -- eax : key |
| 3368 // -- edx : receiver |
| 3369 // -- esp[0] : return address |
| 3370 // ----------------------------------- |
| 3371 Label slow, failed_allocation; |
| 3372 |
| 3373 // Check that the object isn't a smi. |
| 3374 __ test(edx, Immediate(kSmiTagMask)); |
| 3375 __ j(zero, &slow, not_taken); |
| 3376 |
| 3377 // Check that the key is a smi. |
| 3378 __ test(eax, Immediate(kSmiTagMask)); |
| 3379 __ j(not_zero, &slow, not_taken); |
| 3380 |
| 3381 // Get the map of the receiver. |
| 3382 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3383 // Check that the receiver does not require access checks. We need |
| 3384 // to check this explicitly since this generic stub does not perform |
| 3385 // map checks. |
| 3386 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), |
| 3387 1 << Map::kIsAccessCheckNeeded); |
| 3388 __ j(not_zero, &slow, not_taken); |
| 3389 |
| 3390 __ CmpInstanceType(ecx, JS_OBJECT_TYPE); |
| 3391 __ j(not_equal, &slow, not_taken); |
| 3392 |
| 3393 // Check that the elements array is the appropriate type of |
| 3394 // ExternalArray. |
| 3395 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3396 Handle<Map> map(Heap::MapForExternalArrayType(array_type)); |
| 3397 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 3398 Immediate(map)); |
| 3399 __ j(not_equal, &slow, not_taken); |
| 3400 |
| 3401 // eax: key, known to be a smi. |
| 3402 // edx: receiver, known to be a JSObject. |
| 3403 // ebx: elements object, known to be an external array. |
| 3404 // Check that the index is in range. |
| 3405 __ mov(ecx, eax); |
| 3406 __ SmiUntag(ecx); // Untag the index. |
| 3407 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); |
| 3408 // Unsigned comparison catches both negative and too-large values. |
| 3409 __ j(above_equal, &slow); |
| 3410 |
| 3411 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); |
| 3412 // ebx: base pointer of external storage |
| 3413 switch (array_type) { |
| 3414 case kExternalByteArray: |
| 3415 __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0)); |
| 3416 break; |
| 3417 case kExternalUnsignedByteArray: |
| 3418 __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0)); |
| 3419 break; |
| 3420 case kExternalShortArray: |
| 3421 __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0)); |
| 3422 break; |
| 3423 case kExternalUnsignedShortArray: |
| 3424 __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0)); |
| 3425 break; |
| 3426 case kExternalIntArray: |
| 3427 case kExternalUnsignedIntArray: |
| 3428 __ mov(ecx, Operand(ebx, ecx, times_4, 0)); |
| 3429 break; |
| 3430 case kExternalFloatArray: |
| 3431 __ fld_s(Operand(ebx, ecx, times_4, 0)); |
| 3432 break; |
| 3433 default: |
| 3434 UNREACHABLE(); |
| 3435 break; |
| 3436 } |
| 3437 |
| 3438 // For integer array types: |
| 3439 // ecx: value |
| 3440 // For floating-point array type: |
| 3441 // FP(0): value |
| 3442 |
| 3443 if (array_type == kExternalIntArray || |
| 3444 array_type == kExternalUnsignedIntArray) { |
| 3445 // For the Int and UnsignedInt array types, we need to see whether |
| 3446 // the value can be represented in a Smi. If not, we need to convert |
| 3447 // it to a HeapNumber. |
| 3448 Label box_int; |
| 3449 if (array_type == kExternalIntArray) { |
| 3450 __ cmp(ecx, 0xC0000000); |
| 3451 __ j(sign, &box_int); |
| 3452 } else { |
| 3453 ASSERT_EQ(array_type, kExternalUnsignedIntArray); |
| 3454 // The test is different for unsigned int values. Since we need |
| 3455 // the value to be in the range of a positive smi, we can't |
| 3456 // handle either of the top two bits being set in the value. |
| 3457 __ test(ecx, Immediate(0xC0000000)); |
| 3458 __ j(not_zero, &box_int); |
| 3459 } |
| 3460 |
| 3461 __ mov(eax, ecx); |
| 3462 __ SmiTag(eax); |
| 3463 __ ret(0); |
| 3464 |
| 3465 __ bind(&box_int); |
| 3466 |
| 3467 // Allocate a HeapNumber for the int and perform int-to-double |
| 3468 // conversion. |
| 3469 if (array_type == kExternalIntArray) { |
| 3470 __ push(ecx); |
| 3471 __ fild_s(Operand(esp, 0)); |
| 3472 __ pop(ecx); |
| 3473 } else { |
| 3474 ASSERT(array_type == kExternalUnsignedIntArray); |
| 3475 // Need to zero-extend the value. |
| 3476 // There's no fild variant for unsigned values, so zero-extend |
| 3477 // to a 64-bit int manually. |
| 3478 __ push(Immediate(0)); |
| 3479 __ push(ecx); |
| 3480 __ fild_d(Operand(esp, 0)); |
| 3481 __ pop(ecx); |
| 3482 __ pop(ecx); |
| 3483 } |
| 3484 // FP(0): value |
| 3485 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); |
| 3486 // Set the value. |
| 3487 __ mov(eax, ecx); |
| 3488 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3489 __ ret(0); |
| 3490 } else if (array_type == kExternalFloatArray) { |
| 3491 // For the floating-point array type, we need to always allocate a |
| 3492 // HeapNumber. |
| 3493 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation); |
| 3494 // Set the value. |
| 3495 __ mov(eax, ecx); |
| 3496 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3497 __ ret(0); |
| 3498 } else { |
| 3499 __ mov(eax, ecx); |
| 3500 __ SmiTag(eax); |
| 3501 __ ret(0); |
| 3502 } |
| 3503 |
| 3504 // If we fail allocation of the HeapNumber, we still have a value on |
| 3505 // top of the FPU stack. Remove it. |
| 3506 __ bind(&failed_allocation); |
| 3507 __ ffree(); |
| 3508 __ fincstp(); |
| 3509 // Fall through to slow case. |
| 3510 |
| 3511 // Slow case: Jump to runtime. |
| 3512 __ bind(&slow); |
| 3513 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1); |
| 3514 // ----------- S t a t e ------------- |
| 3515 // -- eax : key |
| 3516 // -- edx : receiver |
| 3517 // -- esp[0] : return address |
| 3518 // ----------------------------------- |
| 3519 |
| 3520 __ pop(ebx); |
| 3521 __ push(edx); // receiver |
| 3522 __ push(eax); // name |
| 3523 __ push(ebx); // return address |
| 3524 |
| 3525 // Perform tail call to the entry. |
| 3526 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); |
| 3527 |
| 3528 // Return the generated code. |
| 3529 return GetCode(flags); |
| 3530 } |
| 3531 |
| 3532 |
| 3533 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( |
| 3534 ExternalArrayType array_type, Code::Flags flags) { |
| 3535 // ----------- S t a t e ------------- |
| 3536 // -- eax : value |
| 3537 // -- ecx : key |
| 3538 // -- edx : receiver |
| 3539 // -- esp[0] : return address |
| 3540 // ----------------------------------- |
| 3541 Label slow, check_heap_number; |
| 3542 |
| 3543 // Check that the object isn't a smi. |
| 3544 __ test(edx, Immediate(kSmiTagMask)); |
| 3545 __ j(zero, &slow); |
| 3546 // Get the map from the receiver. |
| 3547 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3548 // Check that the receiver does not require access checks. We need |
| 3549 // to do this because this generic stub does not perform map checks. |
| 3550 __ test_b(FieldOperand(edi, Map::kBitFieldOffset), |
| 3551 1 << Map::kIsAccessCheckNeeded); |
| 3552 __ j(not_zero, &slow); |
| 3553 // Check that the key is a smi. |
| 3554 __ test(ecx, Immediate(kSmiTagMask)); |
| 3555 __ j(not_zero, &slow); |
| 3556 // Get the instance type from the map of the receiver. |
| 3557 __ CmpInstanceType(edi, JS_OBJECT_TYPE); |
| 3558 __ j(not_equal, &slow); |
| 3559 |
| 3560 // Check that the elements array is the appropriate type of |
| 3561 // ExternalArray. |
| 3562 // eax: value |
| 3563 // edx: receiver, a JSObject |
| 3564 // ecx: key, a smi |
| 3565 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3566 __ CheckMap(edi, Handle<Map>(Heap::MapForExternalArrayType(array_type)), |
| 3567 &slow, true); |
| 3568 |
| 3569 // Check that the index is in range. |
| 3570 __ mov(ebx, ecx); |
| 3571 __ SmiUntag(ebx); |
| 3572 __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset)); |
| 3573 // Unsigned comparison catches both negative and too-large values. |
| 3574 __ j(above_equal, &slow); |
| 3575 |
| 3576 // Handle both smis and HeapNumbers in the fast path. Go to the |
| 3577 // runtime for all other kinds of values. |
| 3578 // eax: value |
| 3579 // edx: receiver |
| 3580 // ecx: key |
| 3581 // edi: elements array |
| 3582 // ebx: untagged index |
| 3583 __ test(eax, Immediate(kSmiTagMask)); |
| 3584 __ j(not_equal, &check_heap_number); |
| 3585 // smi case |
| 3586 __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed. |
| 3587 __ SmiUntag(ecx); |
| 3588 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); |
| 3589 // ecx: base pointer of external storage |
| 3590 switch (array_type) { |
| 3591 case kExternalByteArray: |
| 3592 case kExternalUnsignedByteArray: |
| 3593 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3594 break; |
| 3595 case kExternalShortArray: |
| 3596 case kExternalUnsignedShortArray: |
| 3597 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); |
| 3598 break; |
| 3599 case kExternalIntArray: |
| 3600 case kExternalUnsignedIntArray: |
| 3601 __ mov(Operand(edi, ebx, times_4, 0), ecx); |
| 3602 break; |
| 3603 case kExternalFloatArray: |
| 3604 // Need to perform int-to-float conversion. |
| 3605 __ push(ecx); |
| 3606 __ fild_s(Operand(esp, 0)); |
| 3607 __ pop(ecx); |
| 3608 __ fstp_s(Operand(edi, ebx, times_4, 0)); |
| 3609 break; |
| 3610 default: |
| 3611 UNREACHABLE(); |
| 3612 break; |
| 3613 } |
| 3614 __ ret(0); // Return the original value. |
| 3615 |
| 3616 __ bind(&check_heap_number); |
| 3617 // eax: value |
| 3618 // edx: receiver |
| 3619 // ecx: key |
| 3620 // edi: elements array |
| 3621 // ebx: untagged index |
| 3622 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 3623 Immediate(Factory::heap_number_map())); |
| 3624 __ j(not_equal, &slow); |
| 3625 |
| 3626 // The WebGL specification leaves the behavior of storing NaN and |
| 3627 // +/-Infinity into integer arrays basically undefined. For more |
| 3628 // reproducible behavior, convert these to zero. |
| 3629 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); |
| 3630 // ebx: untagged index |
| 3631 // edi: base pointer of external storage |
| 3632 if (array_type == kExternalFloatArray) { |
| 3633 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3634 __ fstp_s(Operand(edi, ebx, times_4, 0)); |
| 3635 __ ret(0); |
| 3636 } else { |
| 3637 // Perform float-to-int conversion with truncation (round-to-zero) |
| 3638 // behavior. |
| 3639 |
| 3640 // For the moment we make the slow call to the runtime on |
| 3641 // processors that don't support SSE2. The code in IntegerConvert |
| 3642 // (code-stubs-ia32.cc) is roughly what is needed here though the |
| 3643 // conversion failure case does not need to be handled. |
| 3644 if (CpuFeatures::IsSupported(SSE2)) { |
| 3645 if (array_type != kExternalIntArray && |
| 3646 array_type != kExternalUnsignedIntArray) { |
| 3647 ASSERT(CpuFeatures::IsSupported(SSE2)); |
| 3648 CpuFeatures::Scope scope(SSE2); |
| 3649 __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3650 // ecx: untagged integer value |
| 3651 switch (array_type) { |
| 3652 case kExternalByteArray: |
| 3653 case kExternalUnsignedByteArray: |
| 3654 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3655 break; |
| 3656 case kExternalShortArray: |
| 3657 case kExternalUnsignedShortArray: |
| 3658 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); |
| 3659 break; |
| 3660 default: |
| 3661 UNREACHABLE(); |
| 3662 break; |
| 3663 } |
| 3664 } else { |
| 3665 if (CpuFeatures::IsSupported(SSE3)) { |
| 3666 CpuFeatures::Scope scope(SSE3); |
| 3667 // fisttp stores values as signed integers. To represent the |
| 3668 // entire range of int and unsigned int arrays, store as a |
| 3669 // 64-bit int and discard the high 32 bits. |
| 3670 // If the value is NaN or +/-infinity, the result is 0x80000000, |
| 3671 // which is automatically zero when taken mod 2^n, n < 32. |
| 3672 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3673 __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
| 3674 __ fisttp_d(Operand(esp, 0)); |
| 3675 __ pop(ecx); |
| 3676 __ add(Operand(esp), Immediate(kPointerSize)); |
| 3677 } else { |
| 3678 ASSERT(CpuFeatures::IsSupported(SSE2)); |
| 3679 CpuFeatures::Scope scope(SSE2); |
| 3680 // We can easily implement the correct rounding behavior for the |
| 3681 // range [0, 2^31-1]. For the time being, to keep this code simple, |
| 3682 // make the slow runtime call for values outside this range. |
| 3683 // Note: we could do better for signed int arrays. |
| 3684 __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3685 // We will need the key if we have to make the slow runtime call. |
| 3686 __ push(ecx); |
| 3687 __ LoadPowerOf2(xmm1, ecx, 31); |
| 3688 __ pop(ecx); |
| 3689 __ ucomisd(xmm1, xmm0); |
| 3690 __ j(above_equal, &slow); |
| 3691 __ cvttsd2si(ecx, Operand(xmm0)); |
| 3692 } |
| 3693 // ecx: untagged integer value |
| 3694 __ mov(Operand(edi, ebx, times_4, 0), ecx); |
| 3695 } |
| 3696 __ ret(0); // Return original value. |
| 3697 } |
| 3698 } |
| 3699 |
| 3700 // Slow case: call runtime. |
| 3701 __ bind(&slow); |
| 3702 // ----------- S t a t e ------------- |
| 3703 // -- eax : value |
| 3704 // -- ecx : key |
| 3705 // -- edx : receiver |
| 3706 // -- esp[0] : return address |
| 3707 // ----------------------------------- |
| 3708 |
| 3709 __ pop(ebx); |
| 3710 __ push(edx); |
| 3711 __ push(ecx); |
| 3712 __ push(eax); |
| 3713 __ push(ebx); |
| 3714 |
| 3715 // Do tail-call to runtime routine. |
| 3716 __ TailCallRuntime(Runtime::kSetProperty, 3, 1); |
| 3717 |
| 3718 return GetCode(flags); |
| 3719 } |
| 3720 |
| 3721 |
| 3289 #undef __ | 3722 #undef __ |
| 3290 | 3723 |
| 3291 } } // namespace v8::internal | 3724 } } // namespace v8::internal |
| 3292 | 3725 |
| 3293 #endif // V8_TARGET_ARCH_IA32 | 3726 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |