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

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

Issue 6597029: [Isolates] Merge r 6300:6500 from bleeding_edge to isolates. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/isolates/
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/ia32/macro-assembler-ia32.cc ('k') | src/ic.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 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 312 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 ASSERT(kNotStringTag != 0); 323 ASSERT(kNotStringTag != 0);
324 __ test(scratch, Immediate(kNotStringTag)); 324 __ test(scratch, Immediate(kNotStringTag));
325 __ j(not_zero, non_string_object, not_taken); 325 __ j(not_zero, non_string_object, not_taken);
326 } 326 }
327 327
328 328
329 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, 329 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm,
330 Register receiver, 330 Register receiver,
331 Register scratch1, 331 Register scratch1,
332 Register scratch2, 332 Register scratch2,
333 Label* miss) { 333 Label* miss,
334 bool support_wrappers) {
334 Label check_wrapper; 335 Label check_wrapper;
335 336
336 // Check if the object is a string leaving the instance type in the 337 // Check if the object is a string leaving the instance type in the
337 // scratch register. 338 // scratch register.
338 GenerateStringCheck(masm, receiver, scratch1, miss, &check_wrapper); 339 GenerateStringCheck(masm, receiver, scratch1, miss,
340 support_wrappers ? &check_wrapper : miss);
339 341
340 // Load length from the string and convert to a smi. 342 // Load length from the string and convert to a smi.
341 __ mov(eax, FieldOperand(receiver, String::kLengthOffset)); 343 __ mov(eax, FieldOperand(receiver, String::kLengthOffset));
342 __ ret(0); 344 __ ret(0);
343 345
344 // Check if the object is a JSValue wrapper. 346 if (support_wrappers) {
345 __ bind(&check_wrapper); 347 // Check if the object is a JSValue wrapper.
346 __ cmp(scratch1, JS_VALUE_TYPE); 348 __ bind(&check_wrapper);
347 __ j(not_equal, miss, not_taken); 349 __ cmp(scratch1, JS_VALUE_TYPE);
350 __ j(not_equal, miss, not_taken);
348 351
349 // Check if the wrapped value is a string and load the length 352 // Check if the wrapped value is a string and load the length
350 // directly if it is. 353 // directly if it is.
351 __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); 354 __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset));
352 GenerateStringCheck(masm, scratch2, scratch1, miss, miss); 355 GenerateStringCheck(masm, scratch2, scratch1, miss, miss);
353 __ mov(eax, FieldOperand(scratch2, String::kLengthOffset)); 356 __ mov(eax, FieldOperand(scratch2, String::kLengthOffset));
354 __ ret(0); 357 __ ret(0);
358 }
355 } 359 }
356 360
357 361
358 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm, 362 void StubCompiler::GenerateLoadFunctionPrototype(MacroAssembler* masm,
359 Register receiver, 363 Register receiver,
360 Register scratch1, 364 Register scratch1,
361 Register scratch2, 365 Register scratch2,
362 Label* miss_label) { 366 Label* miss_label) {
363 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label); 367 __ TryGetFunctionPrototype(receiver, scratch1, scratch2, miss_label);
364 __ mov(eax, Operand(scratch1)); 368 __ mov(eax, Operand(scratch1));
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal 451 // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal
448 // frame. 452 // frame.
449 // ----------------------------------- 453 // -----------------------------------
450 __ pop(scratch); 454 __ pop(scratch);
451 __ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments)); 455 __ add(Operand(esp), Immediate(kPointerSize * kFastApiCallArguments));
452 __ push(scratch); 456 __ push(scratch);
453 } 457 }
454 458
455 459
456 // Generates call to API function. 460 // Generates call to API function.
457 static bool GenerateFastApiCall(MacroAssembler* masm, 461 static MaybeObject* GenerateFastApiCall(MacroAssembler* masm,
458 const CallOptimization& optimization, 462 const CallOptimization& optimization,
459 int argc, 463 int argc) {
460 Failure** failure) {
461 // ----------- S t a t e ------------- 464 // ----------- S t a t e -------------
462 // -- esp[0] : return address 465 // -- esp[0] : return address
463 // -- esp[4] : object passing the type check 466 // -- esp[4] : object passing the type check
464 // (last fast api call extra argument, 467 // (last fast api call extra argument,
465 // set by CheckPrototypes) 468 // set by CheckPrototypes)
466 // -- esp[8] : api function 469 // -- esp[8] : api function
467 // (first fast api call extra argument) 470 // (first fast api call extra argument)
468 // -- esp[12] : api call data 471 // -- esp[12] : api call data
469 // -- esp[16] : last argument 472 // -- esp[16] : last argument
470 // -- ... 473 // -- ...
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
512 __ Set(ApiParameterOperand(4), Immediate(0)); 515 __ Set(ApiParameterOperand(4), Immediate(0));
513 516
514 // v8::InvocationCallback's argument. 517 // v8::InvocationCallback's argument.
515 __ lea(eax, ApiParameterOperand(1)); 518 __ lea(eax, ApiParameterOperand(1));
516 __ mov(ApiParameterOperand(0), eax); 519 __ mov(ApiParameterOperand(0), eax);
517 520
518 // Emitting a stub call may try to allocate (if the code is not 521 // Emitting a stub call may try to allocate (if the code is not
519 // already generated). Do not allow the assembler to perform a 522 // already generated). Do not allow the assembler to perform a
520 // garbage collection but instead return the allocation failure 523 // garbage collection but instead return the allocation failure
521 // object. 524 // object.
522 MaybeObject* result = 525 return masm->TryCallApiFunctionAndReturn(&fun,
523 masm->TryCallApiFunctionAndReturn(&fun, argc + kFastApiCallArguments + 1); 526 argc + kFastApiCallArguments + 1);
524 if (result->IsFailure()) {
525 *failure = Failure::cast(result);
526 return false;
527 }
528 return true;
529 } 527 }
530 528
531 529
532 class CallInterceptorCompiler BASE_EMBEDDED { 530 class CallInterceptorCompiler BASE_EMBEDDED {
533 public: 531 public:
534 CallInterceptorCompiler(StubCompiler* stub_compiler, 532 CallInterceptorCompiler(StubCompiler* stub_compiler,
535 const ParameterCount& arguments, 533 const ParameterCount& arguments,
536 Register name) 534 Register name)
537 : stub_compiler_(stub_compiler), 535 : stub_compiler_(stub_compiler),
538 arguments_(arguments), 536 arguments_(arguments),
539 name_(name) {} 537 name_(name) {}
540 538
541 bool Compile(MacroAssembler* masm, 539 MaybeObject* Compile(MacroAssembler* masm,
542 JSObject* object, 540 JSObject* object,
543 JSObject* holder, 541 JSObject* holder,
544 String* name, 542 String* name,
545 LookupResult* lookup, 543 LookupResult* lookup,
546 Register receiver, 544 Register receiver,
547 Register scratch1, 545 Register scratch1,
548 Register scratch2, 546 Register scratch2,
549 Register scratch3, 547 Register scratch3,
550 Label* miss, 548 Label* miss) {
551 Failure** failure) {
552 ASSERT(holder->HasNamedInterceptor()); 549 ASSERT(holder->HasNamedInterceptor());
553 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); 550 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
554 551
555 // Check that the receiver isn't a smi. 552 // Check that the receiver isn't a smi.
556 __ test(receiver, Immediate(kSmiTagMask)); 553 __ test(receiver, Immediate(kSmiTagMask));
557 __ j(zero, miss, not_taken); 554 __ j(zero, miss, not_taken);
558 555
559 CallOptimization optimization(lookup); 556 CallOptimization optimization(lookup);
560 557
561 if (optimization.is_constant_call()) { 558 if (optimization.is_constant_call()) {
562 return CompileCacheable(masm, 559 return CompileCacheable(masm,
563 object, 560 object,
564 receiver, 561 receiver,
565 scratch1, 562 scratch1,
566 scratch2, 563 scratch2,
567 scratch3, 564 scratch3,
568 holder, 565 holder,
569 lookup, 566 lookup,
570 name, 567 name,
571 optimization, 568 optimization,
572 miss, 569 miss);
573 failure);
574 } else { 570 } else {
575 CompileRegular(masm, 571 CompileRegular(masm,
576 object, 572 object,
577 receiver, 573 receiver,
578 scratch1, 574 scratch1,
579 scratch2, 575 scratch2,
580 scratch3, 576 scratch3,
581 name, 577 name,
582 holder, 578 holder,
583 miss); 579 miss);
584 return true; 580 return HEAP->undefined_value(); // Success.
585 } 581 }
586 } 582 }
587 583
588 private: 584 private:
589 bool CompileCacheable(MacroAssembler* masm, 585 MaybeObject* CompileCacheable(MacroAssembler* masm,
590 JSObject* object, 586 JSObject* object,
591 Register receiver, 587 Register receiver,
592 Register scratch1, 588 Register scratch1,
593 Register scratch2, 589 Register scratch2,
594 Register scratch3, 590 Register scratch3,
595 JSObject* interceptor_holder, 591 JSObject* interceptor_holder,
596 LookupResult* lookup, 592 LookupResult* lookup,
597 String* name, 593 String* name,
598 const CallOptimization& optimization, 594 const CallOptimization& optimization,
599 Label* miss_label, 595 Label* miss_label) {
600 Failure** failure) {
601 ASSERT(optimization.is_constant_call()); 596 ASSERT(optimization.is_constant_call());
602 ASSERT(!lookup->holder()->IsGlobalObject()); 597 ASSERT(!lookup->holder()->IsGlobalObject());
603 598
604 int depth1 = kInvalidProtoDepth; 599 int depth1 = kInvalidProtoDepth;
605 int depth2 = kInvalidProtoDepth; 600 int depth2 = kInvalidProtoDepth;
606 bool can_do_fast_api_call = false; 601 bool can_do_fast_api_call = false;
607 if (optimization.is_simple_api_call() && 602 if (optimization.is_simple_api_call() &&
608 !lookup->holder()->IsGlobalObject()) { 603 !lookup->holder()->IsGlobalObject()) {
609 depth1 = 604 depth1 =
610 optimization.GetPrototypeDepthOfExpectedType(object, 605 optimization.GetPrototypeDepthOfExpectedType(object,
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
652 } else { 647 } else {
653 // CheckPrototypes has a side effect of fetching a 'holder' 648 // CheckPrototypes has a side effect of fetching a 'holder'
654 // for API (object which is instanceof for the signature). It's 649 // for API (object which is instanceof for the signature). It's
655 // safe to omit it here, as if present, it should be fetched 650 // safe to omit it here, as if present, it should be fetched
656 // by the previous CheckPrototypes. 651 // by the previous CheckPrototypes.
657 ASSERT(depth2 == kInvalidProtoDepth); 652 ASSERT(depth2 == kInvalidProtoDepth);
658 } 653 }
659 654
660 // Invoke function. 655 // Invoke function.
661 if (can_do_fast_api_call) { 656 if (can_do_fast_api_call) {
662 bool success = GenerateFastApiCall(masm, optimization, 657 MaybeObject* result =
663 arguments_.immediate(), failure); 658 GenerateFastApiCall(masm, optimization, arguments_.immediate());
664 if (!success) { 659 if (result->IsFailure()) return result;
665 return false;
666 }
667 } else { 660 } else {
668 __ InvokeFunction(optimization.constant_function(), arguments_, 661 __ InvokeFunction(optimization.constant_function(), arguments_,
669 JUMP_FUNCTION); 662 JUMP_FUNCTION);
670 } 663 }
671 664
672 // Deferred code for fast API call case---clean preallocated space. 665 // Deferred code for fast API call case---clean preallocated space.
673 if (can_do_fast_api_call) { 666 if (can_do_fast_api_call) {
674 __ bind(&miss_cleanup); 667 __ bind(&miss_cleanup);
675 FreeSpaceForFastApiCall(masm, scratch1); 668 FreeSpaceForFastApiCall(masm, scratch1);
676 __ jmp(miss_label); 669 __ jmp(miss_label);
677 } 670 }
678 671
679 // Invoke a regular function. 672 // Invoke a regular function.
680 __ bind(&regular_invoke); 673 __ bind(&regular_invoke);
681 if (can_do_fast_api_call) { 674 if (can_do_fast_api_call) {
682 FreeSpaceForFastApiCall(masm, scratch1); 675 FreeSpaceForFastApiCall(masm, scratch1);
683 } 676 }
684 677
685 return true; 678 return HEAP->undefined_value(); // Success.
686 } 679 }
687 680
688 void CompileRegular(MacroAssembler* masm, 681 void CompileRegular(MacroAssembler* masm,
689 JSObject* object, 682 JSObject* object,
690 Register receiver, 683 Register receiver,
691 Register scratch1, 684 Register scratch1,
692 Register scratch2, 685 Register scratch2,
693 Register scratch3, 686 Register scratch3,
694 String* name, 687 String* name,
695 JSObject* interceptor_holder, 688 JSObject* interceptor_holder,
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after
1053 Register reg = 1046 Register reg =
1054 CheckPrototypes(object, receiver, holder, 1047 CheckPrototypes(object, receiver, holder,
1055 scratch1, scratch2, scratch3, name, miss); 1048 scratch1, scratch2, scratch3, name, miss);
1056 1049
1057 // Get the value from the properties. 1050 // Get the value from the properties.
1058 GenerateFastPropertyLoad(masm(), eax, reg, holder, index); 1051 GenerateFastPropertyLoad(masm(), eax, reg, holder, index);
1059 __ ret(0); 1052 __ ret(0);
1060 } 1053 }
1061 1054
1062 1055
1063 bool StubCompiler::GenerateLoadCallback(JSObject* object, 1056 MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object,
1064 JSObject* holder, 1057 JSObject* holder,
1065 Register receiver, 1058 Register receiver,
1066 Register name_reg, 1059 Register name_reg,
1067 Register scratch1, 1060 Register scratch1,
1068 Register scratch2, 1061 Register scratch2,
1069 Register scratch3, 1062 Register scratch3,
1070 AccessorInfo* callback, 1063 AccessorInfo* callback,
1071 String* name, 1064 String* name,
1072 Label* miss, 1065 Label* miss) {
1073 Failure** failure) {
1074 // Check that the receiver isn't a smi. 1066 // Check that the receiver isn't a smi.
1075 __ test(receiver, Immediate(kSmiTagMask)); 1067 __ test(receiver, Immediate(kSmiTagMask));
1076 __ j(zero, miss, not_taken); 1068 __ j(zero, miss, not_taken);
1077 1069
1078 // Check that the maps haven't changed. 1070 // Check that the maps haven't changed.
1079 Register reg = 1071 Register reg =
1080 CheckPrototypes(object, receiver, holder, scratch1, 1072 CheckPrototypes(object, receiver, holder, scratch1,
1081 scratch2, scratch3, name, miss); 1073 scratch2, scratch3, name, miss);
1082 1074
1083 Handle<AccessorInfo> callback_handle(callback); 1075 Handle<AccessorInfo> callback_handle(callback);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1118 1110
1119 __ PrepareCallApiFunction(kApiArgc, eax); 1111 __ PrepareCallApiFunction(kApiArgc, eax);
1120 __ mov(ApiParameterOperand(0), ebx); // name. 1112 __ mov(ApiParameterOperand(0), ebx); // name.
1121 __ add(Operand(ebx), Immediate(kPointerSize)); 1113 __ add(Operand(ebx), Immediate(kPointerSize));
1122 __ mov(ApiParameterOperand(1), ebx); // arguments pointer. 1114 __ mov(ApiParameterOperand(1), ebx); // arguments pointer.
1123 1115
1124 // Emitting a stub call may try to allocate (if the code is not 1116 // Emitting a stub call may try to allocate (if the code is not
1125 // already generated). Do not allow the assembler to perform a 1117 // already generated). Do not allow the assembler to perform a
1126 // garbage collection but instead return the allocation failure 1118 // garbage collection but instead return the allocation failure
1127 // object. 1119 // object.
1128 MaybeObject* result = masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace); 1120 return masm()->TryCallApiFunctionAndReturn(&fun, kStackSpace);
1129 if (result->IsFailure()) {
1130 *failure = Failure::cast(result);
1131 return false;
1132 }
1133
1134 return true;
1135 } 1121 }
1136 1122
1137 1123
1138 void StubCompiler::GenerateLoadConstant(JSObject* object, 1124 void StubCompiler::GenerateLoadConstant(JSObject* object,
1139 JSObject* holder, 1125 JSObject* holder,
1140 Register receiver, 1126 Register receiver,
1141 Register scratch1, 1127 Register scratch1,
1142 Register scratch2, 1128 Register scratch2,
1143 Register scratch3, 1129 Register scratch3,
1144 Object* value, 1130 Object* value,
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
1358 Immediate(Handle<SharedFunctionInfo>(function->shared()))); 1344 Immediate(Handle<SharedFunctionInfo>(function->shared())));
1359 __ j(not_equal, miss, not_taken); 1345 __ j(not_equal, miss, not_taken);
1360 } else { 1346 } else {
1361 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function))); 1347 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function)));
1362 __ j(not_equal, miss, not_taken); 1348 __ j(not_equal, miss, not_taken);
1363 } 1349 }
1364 } 1350 }
1365 1351
1366 1352
1367 MaybeObject* CallStubCompiler::GenerateMissBranch() { 1353 MaybeObject* CallStubCompiler::GenerateMissBranch() {
1354 MaybeObject* maybe_obj =
1355 Isolate::Current()->stub_cache()->ComputeCallMiss(
1356 arguments().immediate(), kind_);
1368 Object* obj; 1357 Object* obj;
1369 { MaybeObject* maybe_obj = Isolate::Current()->stub_cache()-> 1358 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1370 ComputeCallMiss(arguments().immediate(), kind_);
1371 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1372 }
1373 __ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); 1359 __ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET);
1374 return obj; 1360 return obj;
1375 } 1361 }
1376 1362
1377 1363
1378 MUST_USE_RESULT MaybeObject* CallStubCompiler::CompileCallField( 1364 MUST_USE_RESULT MaybeObject* CallStubCompiler::CompileCallField(
1379 JSObject* object, 1365 JSObject* object,
1380 JSObject* holder, 1366 JSObject* holder,
1381 int index, 1367 int index,
1382 String* name) { 1368 String* name) {
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after
1681 // -- ... 1667 // -- ...
1682 // -- esp[(argc + 1) * 4] : receiver 1668 // -- esp[(argc + 1) * 4] : receiver
1683 // ----------------------------------- 1669 // -----------------------------------
1684 1670
1685 // If object is not a string, bail out to regular call. 1671 // If object is not a string, bail out to regular call.
1686 if (!object->IsString() || cell != NULL) return HEAP->undefined_value(); 1672 if (!object->IsString() || cell != NULL) return HEAP->undefined_value();
1687 1673
1688 const int argc = arguments().immediate(); 1674 const int argc = arguments().immediate();
1689 1675
1690 Label miss; 1676 Label miss;
1677 Label name_miss;
1691 Label index_out_of_range; 1678 Label index_out_of_range;
1679 Label* index_out_of_range_label = &index_out_of_range;
1692 1680
1693 GenerateNameCheck(name, &miss); 1681 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
1682 index_out_of_range_label = &miss;
1683 }
1684
1685 GenerateNameCheck(name, &name_miss);
1694 1686
1695 // Check that the maps starting from the prototype haven't changed. 1687 // Check that the maps starting from the prototype haven't changed.
1696 GenerateDirectLoadGlobalFunctionPrototype(masm(), 1688 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1697 Context::STRING_FUNCTION_INDEX, 1689 Context::STRING_FUNCTION_INDEX,
1698 eax, 1690 eax,
1699 &miss); 1691 &miss);
1700 ASSERT(object != holder); 1692 ASSERT(object != holder);
1701 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, 1693 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
1702 ebx, edx, edi, name, &miss); 1694 ebx, edx, edi, name, &miss);
1703 1695
1704 Register receiver = ebx; 1696 Register receiver = ebx;
1705 Register index = edi; 1697 Register index = edi;
1706 Register scratch = edx; 1698 Register scratch = edx;
1707 Register result = eax; 1699 Register result = eax;
1708 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); 1700 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
1709 if (argc > 0) { 1701 if (argc > 0) {
1710 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); 1702 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
1711 } else { 1703 } else {
1712 __ Set(index, Immediate(FACTORY->undefined_value())); 1704 __ Set(index, Immediate(FACTORY->undefined_value()));
1713 } 1705 }
1714 1706
1715 StringCharCodeAtGenerator char_code_at_generator(receiver, 1707 StringCharCodeAtGenerator char_code_at_generator(receiver,
1716 index, 1708 index,
1717 scratch, 1709 scratch,
1718 result, 1710 result,
1719 &miss, // When not a string. 1711 &miss, // When not a string.
1720 &miss, // When not a number. 1712 &miss, // When not a number.
1721 &index_out_of_range, 1713 index_out_of_range_label,
1722 STRING_INDEX_IS_NUMBER); 1714 STRING_INDEX_IS_NUMBER);
1723 char_code_at_generator.GenerateFast(masm()); 1715 char_code_at_generator.GenerateFast(masm());
1724 __ ret((argc + 1) * kPointerSize); 1716 __ ret((argc + 1) * kPointerSize);
1725 1717
1726 StubRuntimeCallHelper call_helper; 1718 StubRuntimeCallHelper call_helper;
1727 char_code_at_generator.GenerateSlow(masm(), call_helper); 1719 char_code_at_generator.GenerateSlow(masm(), call_helper);
1728 1720
1729 __ bind(&index_out_of_range); 1721 if (index_out_of_range.is_linked()) {
1730 __ Set(eax, Immediate(FACTORY->nan_value())); 1722 __ bind(&index_out_of_range);
1731 __ ret((argc + 1) * kPointerSize); 1723 __ Set(eax, Immediate(FACTORY->nan_value()));
1724 __ ret((argc + 1) * kPointerSize);
1725 }
1732 1726
1733 __ bind(&miss); 1727 __ bind(&miss);
1728 // Restore function name in ecx.
1729 __ Set(ecx, Immediate(Handle<String>(name)));
1730 __ bind(&name_miss);
1734 Object* obj; 1731 Object* obj;
1735 { MaybeObject* maybe_obj = GenerateMissBranch(); 1732 { MaybeObject* maybe_obj = GenerateMissBranch();
1736 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1733 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1737 } 1734 }
1738 1735
1739 // Return the generated code. 1736 // Return the generated code.
1740 return GetCode(function); 1737 return GetCode(function);
1741 } 1738 }
1742 1739
1743 1740
(...skipping 10 matching lines...) Expand all
1754 // -- ... 1751 // -- ...
1755 // -- esp[(argc + 1) * 4] : receiver 1752 // -- esp[(argc + 1) * 4] : receiver
1756 // ----------------------------------- 1753 // -----------------------------------
1757 1754
1758 // If object is not a string, bail out to regular call. 1755 // If object is not a string, bail out to regular call.
1759 if (!object->IsString() || cell != NULL) return HEAP->undefined_value(); 1756 if (!object->IsString() || cell != NULL) return HEAP->undefined_value();
1760 1757
1761 const int argc = arguments().immediate(); 1758 const int argc = arguments().immediate();
1762 1759
1763 Label miss; 1760 Label miss;
1761 Label name_miss;
1764 Label index_out_of_range; 1762 Label index_out_of_range;
1763 Label* index_out_of_range_label = &index_out_of_range;
1765 1764
1766 GenerateNameCheck(name, &miss); 1765 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) {
1766 index_out_of_range_label = &miss;
1767 }
1768
1769 GenerateNameCheck(name, &name_miss);
1767 1770
1768 // Check that the maps starting from the prototype haven't changed. 1771 // Check that the maps starting from the prototype haven't changed.
1769 GenerateDirectLoadGlobalFunctionPrototype(masm(), 1772 GenerateDirectLoadGlobalFunctionPrototype(masm(),
1770 Context::STRING_FUNCTION_INDEX, 1773 Context::STRING_FUNCTION_INDEX,
1771 eax, 1774 eax,
1772 &miss); 1775 &miss);
1773 ASSERT(object != holder); 1776 ASSERT(object != holder);
1774 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, 1777 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
1775 ebx, edx, edi, name, &miss); 1778 ebx, edx, edi, name, &miss);
1776 1779
1777 Register receiver = eax; 1780 Register receiver = eax;
1778 Register index = edi; 1781 Register index = edi;
1779 Register scratch1 = ebx; 1782 Register scratch1 = ebx;
1780 Register scratch2 = edx; 1783 Register scratch2 = edx;
1781 Register result = eax; 1784 Register result = eax;
1782 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); 1785 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize));
1783 if (argc > 0) { 1786 if (argc > 0) {
1784 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); 1787 __ mov(index, Operand(esp, (argc - 0) * kPointerSize));
1785 } else { 1788 } else {
1786 __ Set(index, Immediate(FACTORY->undefined_value())); 1789 __ Set(index, Immediate(FACTORY->undefined_value()));
1787 } 1790 }
1788 1791
1789 StringCharAtGenerator char_at_generator(receiver, 1792 StringCharAtGenerator char_at_generator(receiver,
1790 index, 1793 index,
1791 scratch1, 1794 scratch1,
1792 scratch2, 1795 scratch2,
1793 result, 1796 result,
1794 &miss, // When not a string. 1797 &miss, // When not a string.
1795 &miss, // When not a number. 1798 &miss, // When not a number.
1796 &index_out_of_range, 1799 index_out_of_range_label,
1797 STRING_INDEX_IS_NUMBER); 1800 STRING_INDEX_IS_NUMBER);
1798 char_at_generator.GenerateFast(masm()); 1801 char_at_generator.GenerateFast(masm());
1799 __ ret((argc + 1) * kPointerSize); 1802 __ ret((argc + 1) * kPointerSize);
1800 1803
1801 StubRuntimeCallHelper call_helper; 1804 StubRuntimeCallHelper call_helper;
1802 char_at_generator.GenerateSlow(masm(), call_helper); 1805 char_at_generator.GenerateSlow(masm(), call_helper);
1803 1806
1804 __ bind(&index_out_of_range); 1807 if (index_out_of_range.is_linked()) {
1805 __ Set(eax, Immediate(FACTORY->empty_string())); 1808 __ bind(&index_out_of_range);
1806 __ ret((argc + 1) * kPointerSize); 1809 __ Set(eax, Immediate(FACTORY->empty_string()));
1810 __ ret((argc + 1) * kPointerSize);
1811 }
1807 1812
1808 __ bind(&miss); 1813 __ bind(&miss);
1814 // Restore function name in ecx.
1815 __ Set(ecx, Immediate(Handle<String>(name)));
1816 __ bind(&name_miss);
1809 Object* obj; 1817 Object* obj;
1810 { MaybeObject* maybe_obj = GenerateMissBranch(); 1818 { MaybeObject* maybe_obj = GenerateMissBranch();
1811 if (!maybe_obj->ToObject(&obj)) return maybe_obj; 1819 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1812 } 1820 }
1813 1821
1814 // Return the generated code. 1822 // Return the generated code.
1815 return GetCode(function); 1823 return GetCode(function);
1816 } 1824 }
1817 1825
1818 1826
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after
2256 ebx, edx, edi, name, &miss); 2264 ebx, edx, edi, name, &miss);
2257 } 2265 }
2258 break; 2266 break;
2259 } 2267 }
2260 2268
2261 default: 2269 default:
2262 UNREACHABLE(); 2270 UNREACHABLE();
2263 } 2271 }
2264 2272
2265 if (depth != kInvalidProtoDepth) { 2273 if (depth != kInvalidProtoDepth) {
2266 Failure* failure;
2267 // Move the return address on top of the stack. 2274 // Move the return address on top of the stack.
2268 __ mov(eax, Operand(esp, 3 * kPointerSize)); 2275 __ mov(eax, Operand(esp, 3 * kPointerSize));
2269 __ mov(Operand(esp, 0 * kPointerSize), eax); 2276 __ mov(Operand(esp, 0 * kPointerSize), eax);
2270 2277
2271 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains 2278 // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains
2272 // duplicate of return address and will be overwritten. 2279 // duplicate of return address and will be overwritten.
2273 bool success = GenerateFastApiCall(masm(), optimization, argc, &failure); 2280 MaybeObject* result = GenerateFastApiCall(masm(), optimization, argc);
2274 if (!success) { 2281 if (result->IsFailure()) return result;
2275 return failure;
2276 }
2277 } else { 2282 } else {
2278 __ InvokeFunction(function, arguments(), JUMP_FUNCTION); 2283 __ InvokeFunction(function, arguments(), JUMP_FUNCTION);
2279 } 2284 }
2280 2285
2281 // Handle call cache miss. 2286 // Handle call cache miss.
2282 __ bind(&miss); 2287 __ bind(&miss);
2283 if (depth != kInvalidProtoDepth) { 2288 if (depth != kInvalidProtoDepth) {
2284 __ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); 2289 __ add(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize));
2285 } 2290 }
2286 __ bind(&miss_in_smi_check); 2291 __ bind(&miss_in_smi_check);
(...skipping 24 matching lines...) Expand all
2311 // Get the number of arguments. 2316 // Get the number of arguments.
2312 const int argc = arguments().immediate(); 2317 const int argc = arguments().immediate();
2313 2318
2314 LookupResult lookup; 2319 LookupResult lookup;
2315 LookupPostInterceptor(holder, name, &lookup); 2320 LookupPostInterceptor(holder, name, &lookup);
2316 2321
2317 // Get the receiver from the stack. 2322 // Get the receiver from the stack.
2318 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 2323 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2319 2324
2320 CallInterceptorCompiler compiler(this, arguments(), ecx); 2325 CallInterceptorCompiler compiler(this, arguments(), ecx);
2321 Failure* failure; 2326 MaybeObject* result = compiler.Compile(masm(),
2322 bool success = compiler.Compile(masm(), 2327 object,
2323 object, 2328 holder,
2324 holder, 2329 name,
2325 name, 2330 &lookup,
2326 &lookup, 2331 edx,
2327 edx, 2332 ebx,
2328 ebx, 2333 edi,
2329 edi, 2334 eax,
2330 eax, 2335 &miss);
2331 &miss, 2336 if (result->IsFailure()) return result;
2332 &failure);
2333 if (!success) {
2334 return failure;
2335 }
2336 2337
2337 // Restore receiver. 2338 // Restore receiver.
2338 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); 2339 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
2339 2340
2340 // Check that the function really is a function. 2341 // Check that the function really is a function.
2341 __ test(eax, Immediate(kSmiTagMask)); 2342 __ test(eax, Immediate(kSmiTagMask));
2342 __ j(zero, &miss, not_taken); 2343 __ j(zero, &miss, not_taken);
2343 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); 2344 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2344 __ j(not_equal, &miss, not_taken); 2345 __ j(not_equal, &miss, not_taken);
2345 2346
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after
2781 JSObject* object, 2782 JSObject* object,
2782 JSObject* holder, 2783 JSObject* holder,
2783 AccessorInfo* callback) { 2784 AccessorInfo* callback) {
2784 // ----------- S t a t e ------------- 2785 // ----------- S t a t e -------------
2785 // -- eax : receiver 2786 // -- eax : receiver
2786 // -- ecx : name 2787 // -- ecx : name
2787 // -- esp[0] : return address 2788 // -- esp[0] : return address
2788 // ----------------------------------- 2789 // -----------------------------------
2789 Label miss; 2790 Label miss;
2790 2791
2791 Failure* failure = Failure::InternalError(); 2792 MaybeObject* result = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx,
2792 bool success = GenerateLoadCallback(object, holder, eax, ecx, ebx, edx, edi, 2793 edi, callback, name, &miss);
2793 callback, name, &miss, &failure); 2794 if (result->IsFailure()) {
2794 if (!success) {
2795 miss.Unuse(); 2795 miss.Unuse();
2796 return failure; 2796 return result;
2797 } 2797 }
2798 2798
2799 __ bind(&miss); 2799 __ bind(&miss);
2800 GenerateLoadMiss(masm(), Code::LOAD_IC); 2800 GenerateLoadMiss(masm(), Code::LOAD_IC);
2801 2801
2802 // Return the generated code. 2802 // Return the generated code.
2803 return GetCode(CALLBACKS, name); 2803 return GetCode(CALLBACKS, name);
2804 } 2804 }
2805 2805
2806 2806
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
2950 // -- esp[0] : return address 2950 // -- esp[0] : return address
2951 // ----------------------------------- 2951 // -----------------------------------
2952 Label miss; 2952 Label miss;
2953 2953
2954 __ IncrementCounter(COUNTERS->keyed_load_callback(), 1); 2954 __ IncrementCounter(COUNTERS->keyed_load_callback(), 1);
2955 2955
2956 // Check that the name has not changed. 2956 // Check that the name has not changed.
2957 __ cmp(Operand(eax), Immediate(Handle<String>(name))); 2957 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
2958 __ j(not_equal, &miss, not_taken); 2958 __ j(not_equal, &miss, not_taken);
2959 2959
2960 Failure* failure = Failure::InternalError(); 2960 MaybeObject* result = GenerateLoadCallback(receiver, holder, edx, eax, ebx,
2961 bool success = GenerateLoadCallback(receiver, holder, edx, eax, ebx, ecx, edi, 2961 ecx, edi, callback, name, &miss);
2962 callback, name, &miss, &failure); 2962 if (result->IsFailure()) {
2963 if (!success) {
2964 miss.Unuse(); 2963 miss.Unuse();
2965 return failure; 2964 return result;
2966 } 2965 }
2967 2966
2968 __ bind(&miss); 2967 __ bind(&miss);
2969 2968
2970 __ DecrementCounter(COUNTERS->keyed_load_callback(), 1); 2969 __ DecrementCounter(COUNTERS->keyed_load_callback(), 1);
2971 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 2970 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
2972 2971
2973 // Return the generated code. 2972 // Return the generated code.
2974 return GetCode(CALLBACKS, name); 2973 return GetCode(CALLBACKS, name);
2975 } 2974 }
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
3071 // -- esp[0] : return address 3070 // -- esp[0] : return address
3072 // ----------------------------------- 3071 // -----------------------------------
3073 Label miss; 3072 Label miss;
3074 3073
3075 __ IncrementCounter(COUNTERS->keyed_load_string_length(), 1); 3074 __ IncrementCounter(COUNTERS->keyed_load_string_length(), 1);
3076 3075
3077 // Check that the name has not changed. 3076 // Check that the name has not changed.
3078 __ cmp(Operand(eax), Immediate(Handle<String>(name))); 3077 __ cmp(Operand(eax), Immediate(Handle<String>(name)));
3079 __ j(not_equal, &miss, not_taken); 3078 __ j(not_equal, &miss, not_taken);
3080 3079
3081 GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss); 3080 GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true);
3082 __ bind(&miss); 3081 __ bind(&miss);
3083 __ DecrementCounter(COUNTERS->keyed_load_string_length(), 1); 3082 __ DecrementCounter(COUNTERS->keyed_load_string_length(), 1);
3084 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); 3083 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
3085 3084
3086 // Return the generated code. 3085 // Return the generated code.
3087 return GetCode(CALLBACKS, name); 3086 return GetCode(CALLBACKS, name);
3088 } 3087 }
3089 3088
3090 3089
3091 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { 3090 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) {
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
3289 Code* code = Isolate::Current()->builtins()->builtin( 3288 Code* code = Isolate::Current()->builtins()->builtin(
3290 Builtins::JSConstructStubGeneric); 3289 Builtins::JSConstructStubGeneric);
3291 Handle<Code> generic_construct_stub(code); 3290 Handle<Code> generic_construct_stub(code);
3292 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); 3291 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET);
3293 3292
3294 // Return the generated code. 3293 // Return the generated code.
3295 return GetCode(); 3294 return GetCode();
3296 } 3295 }
3297 3296
3298 3297
3298 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub(
3299 ExternalArrayType array_type, Code::Flags flags) {
3300 // ----------- S t a t e -------------
3301 // -- eax : key
3302 // -- edx : receiver
3303 // -- esp[0] : return address
3304 // -----------------------------------
3305 Label slow, failed_allocation;
3306
3307 // Check that the object isn't a smi.
3308 __ test(edx, Immediate(kSmiTagMask));
3309 __ j(zero, &slow, not_taken);
3310
3311 // Check that the key is a smi.
3312 __ test(eax, Immediate(kSmiTagMask));
3313 __ j(not_zero, &slow, not_taken);
3314
3315 // Get the map of the receiver.
3316 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
3317 // Check that the receiver does not require access checks. We need
3318 // to check this explicitly since this generic stub does not perform
3319 // map checks.
3320 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset),
3321 1 << Map::kIsAccessCheckNeeded);
3322 __ j(not_zero, &slow, not_taken);
3323
3324 __ CmpInstanceType(ecx, JS_OBJECT_TYPE);
3325 __ j(not_equal, &slow, not_taken);
3326
3327 // Check that the elements array is the appropriate type of
3328 // ExternalArray.
3329 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset));
3330 Handle<Map> map(HEAP->MapForExternalArrayType(array_type));
3331 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset),
3332 Immediate(map));
3333 __ j(not_equal, &slow, not_taken);
3334
3335 // eax: key, known to be a smi.
3336 // edx: receiver, known to be a JSObject.
3337 // ebx: elements object, known to be an external array.
3338 // Check that the index is in range.
3339 __ mov(ecx, eax);
3340 __ SmiUntag(ecx); // Untag the index.
3341 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset));
3342 // Unsigned comparison catches both negative and too-large values.
3343 __ j(above_equal, &slow);
3344
3345 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset));
3346 // ebx: base pointer of external storage
3347 switch (array_type) {
3348 case kExternalByteArray:
3349 __ movsx_b(ecx, Operand(ebx, ecx, times_1, 0));
3350 break;
3351 case kExternalUnsignedByteArray:
3352 __ movzx_b(ecx, Operand(ebx, ecx, times_1, 0));
3353 break;
3354 case kExternalShortArray:
3355 __ movsx_w(ecx, Operand(ebx, ecx, times_2, 0));
3356 break;
3357 case kExternalUnsignedShortArray:
3358 __ movzx_w(ecx, Operand(ebx, ecx, times_2, 0));
3359 break;
3360 case kExternalIntArray:
3361 case kExternalUnsignedIntArray:
3362 __ mov(ecx, Operand(ebx, ecx, times_4, 0));
3363 break;
3364 case kExternalFloatArray:
3365 __ fld_s(Operand(ebx, ecx, times_4, 0));
3366 break;
3367 default:
3368 UNREACHABLE();
3369 break;
3370 }
3371
3372 // For integer array types:
3373 // ecx: value
3374 // For floating-point array type:
3375 // FP(0): value
3376
3377 if (array_type == kExternalIntArray ||
3378 array_type == kExternalUnsignedIntArray) {
3379 // For the Int and UnsignedInt array types, we need to see whether
3380 // the value can be represented in a Smi. If not, we need to convert
3381 // it to a HeapNumber.
3382 Label box_int;
3383 if (array_type == kExternalIntArray) {
3384 __ cmp(ecx, 0xC0000000);
3385 __ j(sign, &box_int);
3386 } else {
3387 ASSERT_EQ(array_type, kExternalUnsignedIntArray);
3388 // The test is different for unsigned int values. Since we need
3389 // the value to be in the range of a positive smi, we can't
3390 // handle either of the top two bits being set in the value.
3391 __ test(ecx, Immediate(0xC0000000));
3392 __ j(not_zero, &box_int);
3393 }
3394
3395 __ mov(eax, ecx);
3396 __ SmiTag(eax);
3397 __ ret(0);
3398
3399 __ bind(&box_int);
3400
3401 // Allocate a HeapNumber for the int and perform int-to-double
3402 // conversion.
3403 if (array_type == kExternalIntArray) {
3404 __ push(ecx);
3405 __ fild_s(Operand(esp, 0));
3406 __ pop(ecx);
3407 } else {
3408 ASSERT(array_type == kExternalUnsignedIntArray);
3409 // Need to zero-extend the value.
3410 // There's no fild variant for unsigned values, so zero-extend
3411 // to a 64-bit int manually.
3412 __ push(Immediate(0));
3413 __ push(ecx);
3414 __ fild_d(Operand(esp, 0));
3415 __ pop(ecx);
3416 __ pop(ecx);
3417 }
3418 // FP(0): value
3419 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
3420 // Set the value.
3421 __ mov(eax, ecx);
3422 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
3423 __ ret(0);
3424 } else if (array_type == kExternalFloatArray) {
3425 // For the floating-point array type, we need to always allocate a
3426 // HeapNumber.
3427 __ AllocateHeapNumber(ecx, ebx, edi, &failed_allocation);
3428 // Set the value.
3429 __ mov(eax, ecx);
3430 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
3431 __ ret(0);
3432 } else {
3433 __ mov(eax, ecx);
3434 __ SmiTag(eax);
3435 __ ret(0);
3436 }
3437
3438 // If we fail allocation of the HeapNumber, we still have a value on
3439 // top of the FPU stack. Remove it.
3440 __ bind(&failed_allocation);
3441 __ ffree();
3442 __ fincstp();
3443 // Fall through to slow case.
3444
3445 // Slow case: Jump to runtime.
3446 __ bind(&slow);
3447 __ IncrementCounter(COUNTERS->keyed_load_external_array_slow(), 1);
3448 // ----------- S t a t e -------------
3449 // -- eax : key
3450 // -- edx : receiver
3451 // -- esp[0] : return address
3452 // -----------------------------------
3453
3454 __ pop(ebx);
3455 __ push(edx); // receiver
3456 __ push(eax); // name
3457 __ push(ebx); // return address
3458
3459 // Perform tail call to the entry.
3460 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1);
3461
3462 // Return the generated code.
3463 return GetCode(flags);
3464 }
3465
3466
3467 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub(
3468 ExternalArrayType array_type, Code::Flags flags) {
3469 // ----------- S t a t e -------------
3470 // -- eax : value
3471 // -- ecx : key
3472 // -- edx : receiver
3473 // -- esp[0] : return address
3474 // -----------------------------------
3475 Label slow, check_heap_number;
3476
3477 // Check that the object isn't a smi.
3478 __ test(edx, Immediate(kSmiTagMask));
3479 __ j(zero, &slow);
3480 // Get the map from the receiver.
3481 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset));
3482 // Check that the receiver does not require access checks. We need
3483 // to do this because this generic stub does not perform map checks.
3484 __ test_b(FieldOperand(edi, Map::kBitFieldOffset),
3485 1 << Map::kIsAccessCheckNeeded);
3486 __ j(not_zero, &slow);
3487 // Check that the key is a smi.
3488 __ test(ecx, Immediate(kSmiTagMask));
3489 __ j(not_zero, &slow);
3490 // Get the instance type from the map of the receiver.
3491 __ CmpInstanceType(edi, JS_OBJECT_TYPE);
3492 __ j(not_equal, &slow);
3493
3494 // Check that the elements array is the appropriate type of
3495 // ExternalArray.
3496 // eax: value
3497 // edx: receiver, a JSObject
3498 // ecx: key, a smi
3499 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
3500 __ CheckMap(edi, Handle<Map>(HEAP->MapForExternalArrayType(array_type)),
3501 &slow, true);
3502
3503 // Check that the index is in range.
3504 __ mov(ebx, ecx);
3505 __ SmiUntag(ebx);
3506 __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset));
3507 // Unsigned comparison catches both negative and too-large values.
3508 __ j(above_equal, &slow);
3509
3510 // Handle both smis and HeapNumbers in the fast path. Go to the
3511 // runtime for all other kinds of values.
3512 // eax: value
3513 // edx: receiver
3514 // ecx: key
3515 // edi: elements array
3516 // ebx: untagged index
3517 __ test(eax, Immediate(kSmiTagMask));
3518 __ j(not_equal, &check_heap_number);
3519 // smi case
3520 __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed.
3521 __ SmiUntag(ecx);
3522 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
3523 // ecx: base pointer of external storage
3524 switch (array_type) {
3525 case kExternalByteArray:
3526 case kExternalUnsignedByteArray:
3527 __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
3528 break;
3529 case kExternalShortArray:
3530 case kExternalUnsignedShortArray:
3531 __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
3532 break;
3533 case kExternalIntArray:
3534 case kExternalUnsignedIntArray:
3535 __ mov(Operand(edi, ebx, times_4, 0), ecx);
3536 break;
3537 case kExternalFloatArray:
3538 // Need to perform int-to-float conversion.
3539 __ push(ecx);
3540 __ fild_s(Operand(esp, 0));
3541 __ pop(ecx);
3542 __ fstp_s(Operand(edi, ebx, times_4, 0));
3543 break;
3544 default:
3545 UNREACHABLE();
3546 break;
3547 }
3548 __ ret(0); // Return the original value.
3549
3550 __ bind(&check_heap_number);
3551 // eax: value
3552 // edx: receiver
3553 // ecx: key
3554 // edi: elements array
3555 // ebx: untagged index
3556 __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
3557 Immediate(FACTORY->heap_number_map()));
3558 __ j(not_equal, &slow);
3559
3560 // The WebGL specification leaves the behavior of storing NaN and
3561 // +/-Infinity into integer arrays basically undefined. For more
3562 // reproducible behavior, convert these to zero.
3563 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset));
3564 // ebx: untagged index
3565 // edi: base pointer of external storage
3566 if (array_type == kExternalFloatArray) {
3567 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
3568 __ fstp_s(Operand(edi, ebx, times_4, 0));
3569 __ ret(0);
3570 } else {
3571 // Perform float-to-int conversion with truncation (round-to-zero)
3572 // behavior.
3573
3574 // For the moment we make the slow call to the runtime on
3575 // processors that don't support SSE2. The code in IntegerConvert
3576 // (code-stubs-ia32.cc) is roughly what is needed here though the
3577 // conversion failure case does not need to be handled.
3578 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) {
3579 if (array_type != kExternalIntArray &&
3580 array_type != kExternalUnsignedIntArray) {
3581 ASSERT(Isolate::Current()->cpu_features()->IsSupported(SSE2));
3582 CpuFeatures::Scope scope(SSE2);
3583 __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset));
3584 // ecx: untagged integer value
3585 switch (array_type) {
3586 case kExternalByteArray:
3587 case kExternalUnsignedByteArray:
3588 __ mov_b(Operand(edi, ebx, times_1, 0), ecx);
3589 break;
3590 case kExternalShortArray:
3591 case kExternalUnsignedShortArray:
3592 __ mov_w(Operand(edi, ebx, times_2, 0), ecx);
3593 break;
3594 default:
3595 UNREACHABLE();
3596 break;
3597 }
3598 } else {
3599 if (Isolate::Current()->cpu_features()->IsSupported(SSE3)) {
3600 CpuFeatures::Scope scope(SSE3);
3601 // fisttp stores values as signed integers. To represent the
3602 // entire range of int and unsigned int arrays, store as a
3603 // 64-bit int and discard the high 32 bits.
3604 // If the value is NaN or +/-infinity, the result is 0x80000000,
3605 // which is automatically zero when taken mod 2^n, n < 32.
3606 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
3607 __ sub(Operand(esp), Immediate(2 * kPointerSize));
3608 __ fisttp_d(Operand(esp, 0));
3609 __ pop(ecx);
3610 __ add(Operand(esp), Immediate(kPointerSize));
3611 } else {
3612 ASSERT(Isolate::Current()->cpu_features()->IsSupported(SSE2));
3613 CpuFeatures::Scope scope(SSE2);
3614 // We can easily implement the correct rounding behavior for the
3615 // range [0, 2^31-1]. For the time being, to keep this code simple,
3616 // make the slow runtime call for values outside this range.
3617 // Note: we could do better for signed int arrays.
3618 __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset));
3619 // We will need the key if we have to make the slow runtime call.
3620 __ push(ecx);
3621 __ LoadPowerOf2(xmm1, ecx, 31);
3622 __ pop(ecx);
3623 __ ucomisd(xmm1, xmm0);
3624 __ j(above_equal, &slow);
3625 __ cvttsd2si(ecx, Operand(xmm0));
3626 }
3627 // ecx: untagged integer value
3628 __ mov(Operand(edi, ebx, times_4, 0), ecx);
3629 }
3630 __ ret(0); // Return original value.
3631 }
3632 }
3633
3634 // Slow case: call runtime.
3635 __ bind(&slow);
3636 // ----------- S t a t e -------------
3637 // -- eax : value
3638 // -- ecx : key
3639 // -- edx : receiver
3640 // -- esp[0] : return address
3641 // -----------------------------------
3642
3643 __ pop(ebx);
3644 __ push(edx);
3645 __ push(ecx);
3646 __ push(eax);
3647 __ push(ebx);
3648
3649 // Do tail-call to runtime routine.
3650 __ TailCallRuntime(Runtime::kSetProperty, 3, 1);
3651
3652 return GetCode(flags);
3653 }
3654
3655
3299 #undef __ 3656 #undef __
3300 3657
3301 } } // namespace v8::internal 3658 } } // namespace v8::internal
3302 3659
3303 #endif // V8_TARGET_ARCH_IA32 3660 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « src/ia32/macro-assembler-ia32.cc ('k') | src/ic.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698