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 |