| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); | 283 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); |
| 284 __ cmp(scratch, Operand(JS_ARRAY_TYPE)); | 284 __ cmp(scratch, Operand(JS_ARRAY_TYPE)); |
| 285 __ b(ne, miss_label); | 285 __ b(ne, miss_label); |
| 286 | 286 |
| 287 // Load length directly from the JS array. | 287 // Load length directly from the JS array. |
| 288 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); | 288 __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); |
| 289 __ Ret(); | 289 __ Ret(); |
| 290 } | 290 } |
| 291 | 291 |
| 292 | 292 |
| 293 // Generate code to check if an object is a string. If the object is |
| 294 // a string, the map's instance type is left in the scratch1 register. |
| 295 static void GenerateStringCheck(MacroAssembler* masm, |
| 296 Register receiver, |
| 297 Register scratch1, |
| 298 Register scratch2, |
| 299 Label* smi, |
| 300 Label* non_string_object) { |
| 301 // Check that the receiver isn't a smi. |
| 302 __ tst(receiver, Operand(kSmiTagMask)); |
| 303 __ b(eq, smi); |
| 304 |
| 305 // Check that the object is a string. |
| 306 __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| 307 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); |
| 308 __ and_(scratch2, scratch1, Operand(kIsNotStringMask)); |
| 309 // The cast is to resolve the overload for the argument of 0x0. |
| 310 __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag))); |
| 311 __ b(ne, non_string_object); |
| 312 } |
| 313 |
| 314 |
| 315 void StubCompiler::GenerateLoadStringLength2(MacroAssembler* masm, |
| 316 Register receiver, |
| 317 Register scratch1, |
| 318 Register scratch2, |
| 319 Label* miss) { |
| 320 Label load_length, check_wrapper; |
| 321 |
| 322 // Check if the object is a string leaving the instance type in the |
| 323 // scratch1 register. |
| 324 GenerateStringCheck(masm, receiver, scratch1, scratch2, |
| 325 miss, &check_wrapper); |
| 326 |
| 327 // Load length directly from the string. |
| 328 __ bind(&load_length); |
| 329 __ and_(scratch1, scratch1, Operand(kStringSizeMask)); |
| 330 __ add(scratch1, scratch1, Operand(String::kHashShift)); |
| 331 __ ldr(r0, FieldMemOperand(receiver, String::kLengthOffset)); |
| 332 __ mov(r0, Operand(r0, LSR, scratch1)); |
| 333 __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
| 334 __ Ret(); |
| 335 |
| 336 // Check if the object is a JSValue wrapper. |
| 337 __ bind(&check_wrapper); |
| 338 __ cmp(scratch1, Operand(JS_VALUE_TYPE)); |
| 339 __ b(ne, miss); |
| 340 |
| 341 // Check if the wrapped value is a string and load the length |
| 342 // directly if it is. |
| 343 __ ldr(r0, FieldMemOperand(receiver, JSValue::kValueOffset)); |
| 344 GenerateStringCheck(masm, receiver, scratch1, scratch1, miss, miss); |
| 345 __ b(&load_length); |
| 346 } |
| 347 |
| 348 |
| 349 // Generate StoreField code, value is passed in r0 register. |
| 350 // After executing generated code, the receiver_reg and name_reg |
| 351 // may be clobbered. |
| 352 void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
| 353 Builtins::Name storage_extend, |
| 354 JSObject* object, |
| 355 int index, |
| 356 Map* transition, |
| 357 Register receiver_reg, |
| 358 Register name_reg, |
| 359 Register scratch, |
| 360 Label* miss_label) { |
| 361 // r0 : value |
| 362 Label exit; |
| 363 |
| 364 // Check that the receiver isn't a smi. |
| 365 __ tst(receiver_reg, Operand(kSmiTagMask)); |
| 366 __ b(eq, miss_label); |
| 367 |
| 368 // Check that the map of the receiver hasn't changed. |
| 369 __ ldr(scratch, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); |
| 370 __ cmp(scratch, Operand(Handle<Map>(object->map()))); |
| 371 __ b(ne, miss_label); |
| 372 |
| 373 // Perform global security token check if needed. |
| 374 if (object->IsJSGlobalProxy()) { |
| 375 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); |
| 376 } |
| 377 |
| 378 // Stub never generated for non-global objects that require access |
| 379 // checks. |
| 380 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
| 381 |
| 382 // Perform map transition for the receiver if necessary. |
| 383 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) { |
| 384 // The properties must be extended before we can store the value. |
| 385 // We jump to a runtime call that extends the propeties array. |
| 386 __ mov(r2, Operand(Handle<Map>(transition))); |
| 387 // Please note, if we implement keyed store for arm we need |
| 388 // to call the Builtins::KeyedStoreIC_ExtendStorage. |
| 389 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage)); |
| 390 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 391 return; |
| 392 } |
| 393 |
| 394 if (transition != NULL) { |
| 395 // Update the map of the object; no write barrier updating is |
| 396 // needed because the map is never in new space. |
| 397 __ mov(ip, Operand(Handle<Map>(transition))); |
| 398 __ str(ip, FieldMemOperand(receiver_reg, HeapObject::kMapOffset)); |
| 399 } |
| 400 |
| 401 // Adjust for the number of properties stored in the object. Even in the |
| 402 // face of a transition we can use the old map here because the size of the |
| 403 // object and the number of in-object properties is not going to change. |
| 404 index -= object->map()->inobject_properties(); |
| 405 |
| 406 if (index < 0) { |
| 407 // Set the property straight into the object. |
| 408 int offset = object->map()->instance_size() + (index * kPointerSize); |
| 409 __ str(r0, FieldMemOperand(receiver_reg, offset)); |
| 410 |
| 411 // Skip updating write barrier if storing a smi. |
| 412 __ tst(r0, Operand(kSmiTagMask)); |
| 413 __ b(eq, &exit); |
| 414 |
| 415 // Update the write barrier for the array address. |
| 416 // Pass the value being stored in the now unused name_reg. |
| 417 __ mov(name_reg, Operand(offset)); |
| 418 __ RecordWrite(receiver_reg, name_reg, scratch); |
| 419 } else { |
| 420 // Write to the properties array. |
| 421 int offset = index * kPointerSize + Array::kHeaderSize; |
| 422 // Get the properties array |
| 423 __ ldr(scratch, FieldMemOperand(receiver_reg, JSObject::kPropertiesOffset)); |
| 424 __ str(r0, FieldMemOperand(scratch, offset)); |
| 425 |
| 426 // Skip updating write barrier if storing a smi. |
| 427 __ tst(r0, Operand(kSmiTagMask)); |
| 428 __ b(eq, &exit); |
| 429 |
| 430 // Update the write barrier for the array address. |
| 431 // Ok to clobber receiver_reg and name_reg, since we return. |
| 432 __ mov(name_reg, Operand(offset)); |
| 433 __ RecordWrite(scratch, name_reg, receiver_reg); |
| 434 } |
| 435 |
| 436 // Return the value (register r0). |
| 437 __ bind(&exit); |
| 438 __ Ret(); |
| 439 } |
| 440 |
| 441 |
| 293 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { | 442 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { |
| 294 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); | 443 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); |
| 295 Code* code = NULL; | 444 Code* code = NULL; |
| 296 if (kind == Code::LOAD_IC) { | 445 if (kind == Code::LOAD_IC) { |
| 297 code = Builtins::builtin(Builtins::LoadIC_Miss); | 446 code = Builtins::builtin(Builtins::LoadIC_Miss); |
| 298 } else { | 447 } else { |
| 299 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss); | 448 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss); |
| 300 } | 449 } |
| 301 | 450 |
| 302 Handle<Code> ic(code); | 451 Handle<Code> ic(code); |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 545 Map* transition, | 694 Map* transition, |
| 546 String* name) { | 695 String* name) { |
| 547 // ----------- S t a t e ------------- | 696 // ----------- S t a t e ------------- |
| 548 // -- r0 : value | 697 // -- r0 : value |
| 549 // -- r2 : name | 698 // -- r2 : name |
| 550 // -- lr : return address | 699 // -- lr : return address |
| 551 // -- [sp] : receiver | 700 // -- [sp] : receiver |
| 552 // ----------------------------------- | 701 // ----------------------------------- |
| 553 | 702 |
| 554 HandleScope scope; | 703 HandleScope scope; |
| 555 Label miss, exit; | 704 Label miss; |
| 556 | 705 |
| 557 // Get the receiver from the stack. | 706 // Get the receiver from the stack. |
| 558 __ ldr(r3, MemOperand(sp, 0 * kPointerSize)); | 707 __ ldr(r3, MemOperand(sp, 0 * kPointerSize)); |
| 559 | 708 |
| 560 // Check that the receiver isn't a smi. | 709 // name register might be clobbered. |
| 561 __ tst(r3, Operand(kSmiTagMask)); | 710 GenerateStoreField(masm(), |
| 562 __ b(eq, &miss); | 711 Builtins::StoreIC_ExtendStorage, |
| 563 | 712 object, |
| 564 // Check that the map of the receiver hasn't changed. | 713 index, |
| 565 __ ldr(r1, FieldMemOperand(r3, HeapObject::kMapOffset)); | 714 transition, |
| 566 __ cmp(r1, Operand(Handle<Map>(object->map()))); | 715 r3, r2, r1, |
| 567 __ b(ne, &miss); | 716 &miss); |
| 568 | |
| 569 // Perform global security token check if needed. | |
| 570 if (object->IsJSGlobalProxy()) { | |
| 571 __ CheckAccessGlobalProxy(r3, r1, &miss); | |
| 572 } | |
| 573 | |
| 574 // Stub never generated for non-global objects that require access | |
| 575 // checks. | |
| 576 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | |
| 577 | |
| 578 // Perform map transition for the receiver if necessary. | |
| 579 if ((transition != NULL) && (object->map()->unused_property_fields() == 0)) { | |
| 580 // The properties must be extended before we can store the value. | |
| 581 // We jump to a runtime call that extends the propeties array. | |
| 582 __ mov(r2, Operand(Handle<Map>(transition))); | |
| 583 // Please note, if we implement keyed store for arm we need | |
| 584 // to call the Builtins::KeyedStoreIC_ExtendStorage. | |
| 585 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_ExtendStorage)); | |
| 586 __ Jump(ic, RelocInfo::CODE_TARGET); | |
| 587 } else { | |
| 588 // Adjust for the number of properties stored in the object. Even in the | |
| 589 // face of a transition we can use the old map here because the size of the | |
| 590 // object and the number of in-object properties is not going to change. | |
| 591 index -= object->map()->inobject_properties(); | |
| 592 | |
| 593 if (index >= 0) { | |
| 594 // Get the properties array | |
| 595 __ ldr(r1, FieldMemOperand(r3, JSObject::kPropertiesOffset)); | |
| 596 } | |
| 597 | |
| 598 if (transition != NULL) { | |
| 599 // Update the map of the object; no write barrier updating is | |
| 600 // needed because the map is never in new space. | |
| 601 __ mov(ip, Operand(Handle<Map>(transition))); | |
| 602 __ str(ip, FieldMemOperand(r3, HeapObject::kMapOffset)); | |
| 603 } | |
| 604 | |
| 605 if (index < 0) { | |
| 606 // Set the property straight into the object. | |
| 607 int offset = object->map()->instance_size() + (index * kPointerSize); | |
| 608 __ str(r0, FieldMemOperand(r3, offset)); | |
| 609 | |
| 610 // Skip updating write barrier if storing a smi. | |
| 611 __ tst(r0, Operand(kSmiTagMask)); | |
| 612 __ b(eq, &exit); | |
| 613 | |
| 614 // Update the write barrier for the array address. | |
| 615 __ mov(r1, Operand(offset)); | |
| 616 __ RecordWrite(r3, r1, r2); | |
| 617 } else { | |
| 618 // Write to the properties array. | |
| 619 int offset = index * kPointerSize + Array::kHeaderSize; | |
| 620 __ str(r0, FieldMemOperand(r1, offset)); | |
| 621 | |
| 622 // Skip updating write barrier if storing a smi. | |
| 623 __ tst(r0, Operand(kSmiTagMask)); | |
| 624 __ b(eq, &exit); | |
| 625 | |
| 626 // Update the write barrier for the array address. | |
| 627 __ mov(r3, Operand(offset)); | |
| 628 __ RecordWrite(r1, r3, r2); // OK to clobber r2, since we return | |
| 629 } | |
| 630 | |
| 631 // Return the value (register r0). | |
| 632 __ bind(&exit); | |
| 633 __ Ret(); | |
| 634 } | |
| 635 // Handle store cache miss. | |
| 636 __ bind(&miss); | 717 __ bind(&miss); |
| 637 __ mov(r2, Operand(Handle<String>(name))); // restore name | 718 __ mov(r2, Operand(Handle<String>(name))); // restore name |
| 638 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 719 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); |
| 639 __ Jump(ic, RelocInfo::CODE_TARGET); | 720 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 640 | 721 |
| 641 // Return the generated code. | 722 // Return the generated code. |
| 642 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION); | 723 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION); |
| 643 } | 724 } |
| 644 | 725 |
| 645 | 726 |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 971 __ b(ne, &miss); | 1052 __ b(ne, &miss); |
| 972 | 1053 |
| 973 GenerateLoadArrayLength(masm(), r0, r3, &miss); | 1054 GenerateLoadArrayLength(masm(), r0, r3, &miss); |
| 974 __ bind(&miss); | 1055 __ bind(&miss); |
| 975 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 1056 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 976 | 1057 |
| 977 return GetCode(CALLBACKS); | 1058 return GetCode(CALLBACKS); |
| 978 } | 1059 } |
| 979 | 1060 |
| 980 | 1061 |
| 981 // TODO(1224671): implement the fast case. | |
| 982 Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { | 1062 Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { |
| 983 // ----------- S t a t e ------------- | 1063 // ----------- S t a t e ------------- |
| 984 // -- lr : return address | 1064 // -- lr : return address |
| 985 // -- sp[0] : key | 1065 // -- sp[0] : key |
| 986 // -- sp[4] : receiver | 1066 // -- sp[4] : receiver |
| 987 // ----------------------------------- | 1067 // ----------------------------------- |
| 988 HandleScope scope; | 1068 HandleScope scope; |
| 1069 |
| 1070 Label miss; |
| 1071 __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3); |
| 1072 |
| 1073 __ ldr(r2, MemOperand(sp)); |
| 1074 __ ldr(r0, MemOperand(sp, kPointerSize)); // receiver |
| 1075 |
| 1076 __ cmp(r2, Operand(Handle<String>(name))); |
| 1077 __ b(ne, &miss); |
| 1078 |
| 1079 GenerateLoadStringLength2(masm(), r0, r1, r3, &miss); |
| 1080 __ bind(&miss); |
| 1081 __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3); |
| 1082 |
| 989 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 1083 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 990 | 1084 |
| 991 return GetCode(CALLBACKS); | 1085 return GetCode(CALLBACKS); |
| 992 } | 1086 } |
| 993 | 1087 |
| 994 | 1088 |
| 995 // TODO(1224671): implement the fast case. | 1089 // TODO(1224671): implement the fast case. |
| 996 Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { | 1090 Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { |
| 997 // ----------- S t a t e ------------- | 1091 // ----------- S t a t e ------------- |
| 998 // -- lr : return address | 1092 // -- lr : return address |
| 999 // -- sp[0] : key | 1093 // -- sp[0] : key |
| 1000 // -- sp[4] : receiver | 1094 // -- sp[4] : receiver |
| 1001 // ----------------------------------- | 1095 // ----------------------------------- |
| 1002 HandleScope scope; | 1096 HandleScope scope; |
| 1003 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 1097 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 1004 | 1098 |
| 1005 return GetCode(CALLBACKS); | 1099 return GetCode(CALLBACKS); |
| 1006 } | 1100 } |
| 1007 | 1101 |
| 1008 | 1102 |
| 1009 // TODO(1224671): implement the fast case. | |
| 1010 Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, | 1103 Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, |
| 1011 int index, | 1104 int index, |
| 1012 Map* transition, | 1105 Map* transition, |
| 1013 String* name) { | 1106 String* name) { |
| 1014 // ----------- S t a t e ------------- | 1107 // ----------- S t a t e ------------- |
| 1015 // -- r0 : value | 1108 // -- r0 : value |
| 1016 // -- r2 : name | 1109 // -- r2 : name |
| 1017 // -- lr : return address | 1110 // -- lr : return address |
| 1018 // -- [sp] : receiver | 1111 // -- [sp] : receiver |
| 1019 // ----------------------------------- | 1112 // ----------------------------------- |
| 1020 HandleScope scope; | 1113 HandleScope scope; |
| 1114 Label miss; |
| 1115 |
| 1116 __ IncrementCounter(&Counters::keyed_store_field, 1, r1, r3); |
| 1117 |
| 1118 // Check that the name has not changed. |
| 1119 __ cmp(r2, Operand(Handle<String>(name))); |
| 1120 __ b(ne, &miss); |
| 1121 |
| 1122 // Load receiver from the stack. |
| 1123 __ ldr(r3, MemOperand(sp)); |
| 1124 // r1 is used as scratch register, r3 and r2 might be clobbered. |
| 1125 GenerateStoreField(masm(), |
| 1126 Builtins::StoreIC_ExtendStorage, |
| 1127 object, |
| 1128 index, |
| 1129 transition, |
| 1130 r3, r2, r1, |
| 1131 &miss); |
| 1132 __ bind(&miss); |
| 1133 |
| 1134 __ DecrementCounter(&Counters::keyed_store_field, 1, r1, r3); |
| 1135 __ mov(r2, Operand(Handle<String>(name))); // restore name register. |
| 1021 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); | 1136 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); |
| 1022 __ Jump(ic, RelocInfo::CODE_TARGET); | 1137 __ Jump(ic, RelocInfo::CODE_TARGET); |
| 1023 | 1138 |
| 1024 // Return the generated code. | 1139 // Return the generated code. |
| 1025 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION); | 1140 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION); |
| 1026 } | 1141 } |
| 1027 | 1142 |
| 1028 | 1143 |
| 1029 #undef __ | 1144 #undef __ |
| 1030 | 1145 |
| 1031 } } // namespace v8::internal | 1146 } } // namespace v8::internal |
| OLD | NEW |