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