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

Side by Side Diff: runtime/vm/stub_code_x64.cc

Issue 727623002: Support verified heap pointer writes on x64. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 1 month 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
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/globals.h" 5 #include "vm/globals.h"
6 #if defined(TARGET_ARCH_X64) 6 #if defined(TARGET_ARCH_X64)
7 7
8 #include "vm/assembler.h" 8 #include "vm/assembler.h"
9 #include "vm/compiler.h" 9 #include "vm/compiler.h"
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 // RAX: newly allocated array. 359 // RAX: newly allocated array.
360 // R10: length of the array (was preserved by the stub). 360 // R10: length of the array (was preserved by the stub).
361 __ pushq(RAX); // Array is in RAX and on top of stack. 361 __ pushq(RAX); // Array is in RAX and on top of stack.
362 __ leaq(R12, Address(RBP, R10, TIMES_8, kParamEndSlotFromFp * kWordSize)); 362 __ leaq(R12, Address(RBP, R10, TIMES_8, kParamEndSlotFromFp * kWordSize));
363 __ leaq(RBX, FieldAddress(RAX, Array::data_offset())); 363 __ leaq(RBX, FieldAddress(RAX, Array::data_offset()));
364 // R12: address of first argument on stack. 364 // R12: address of first argument on stack.
365 // RBX: address of first argument in array. 365 // RBX: address of first argument in array.
366 Label loop, loop_condition; 366 Label loop, loop_condition;
367 __ jmp(&loop_condition, Assembler::kNearJump); 367 __ jmp(&loop_condition, Assembler::kNearJump);
368 __ Bind(&loop); 368 __ Bind(&loop);
369 __ movq(RAX, Address(R12, 0)); 369 __ movq(RDI, Address(R12, 0));
370 __ movq(Address(RBX, 0), RAX); 370 // No generational barrier needed, since array is in new space.
371 __ StoreIntoObjectNoBarrier(RAX, Address(RBX, 0), RDI);
371 __ addq(RBX, Immediate(kWordSize)); 372 __ addq(RBX, Immediate(kWordSize));
372 __ subq(R12, Immediate(kWordSize)); 373 __ subq(R12, Immediate(kWordSize));
373 __ Bind(&loop_condition); 374 __ Bind(&loop_condition);
374 __ decq(R10); 375 __ decq(R10);
375 __ j(POSITIVE, &loop, Assembler::kNearJump); 376 __ j(POSITIVE, &loop, Assembler::kNearJump);
376 } 377 }
377 378
378 379
379 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, 380 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame,
380 intptr_t deopt_reason, 381 intptr_t deopt_reason,
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 // RCX: new object end address. 646 // RCX: new object end address.
646 // RDI: iterator which initially points to the start of the variable 647 // RDI: iterator which initially points to the start of the variable
647 // data area to be initialized. 648 // data area to be initialized.
648 __ LoadObject(R12, Object::null_object(), PP); 649 __ LoadObject(R12, Object::null_object(), PP);
649 __ leaq(RDI, FieldAddress(RAX, sizeof(RawArray))); 650 __ leaq(RDI, FieldAddress(RAX, sizeof(RawArray)));
650 Label done; 651 Label done;
651 Label init_loop; 652 Label init_loop;
652 __ Bind(&init_loop); 653 __ Bind(&init_loop);
653 __ cmpq(RDI, RCX); 654 __ cmpq(RDI, RCX);
654 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); 655 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump);
655 __ movq(Address(RDI, 0), R12); 656 // No generational barrier needed, since we are storing null.
657 __ StoreIntoObjectNoBarrier(RAX, Address(RDI, 0), R12);
656 __ addq(RDI, Immediate(kWordSize)); 658 __ addq(RDI, Immediate(kWordSize));
657 __ jmp(&init_loop, Assembler::kNearJump); 659 __ jmp(&init_loop, Assembler::kNearJump);
658 __ Bind(&done); 660 __ Bind(&done);
659 __ ret(); // returns the newly allocated object in RAX. 661 __ ret(); // returns the newly allocated object in RAX.
660 662
661 // Unable to allocate the array using the fast inline code, just call 663 // Unable to allocate the array using the fast inline code, just call
662 // into the runtime. 664 // into the runtime.
663 __ Bind(&slow_case); 665 __ Bind(&slow_case);
664 // Create a stub frame as we are pushing some objects on the stack before 666 // Create a stub frame as we are pushing some objects on the stack before
665 // calling into the runtime. 667 // calling into the runtime.
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
878 } 880 }
879 881
880 // Setup up number of context variables field. 882 // Setup up number of context variables field.
881 // RAX: new object. 883 // RAX: new object.
882 // R10: number of context variables as integer value (not object). 884 // R10: number of context variables as integer value (not object).
883 __ movq(FieldAddress(RAX, Context::num_variables_offset()), R10); 885 __ movq(FieldAddress(RAX, Context::num_variables_offset()), R10);
884 886
885 // Setup the parent field. 887 // Setup the parent field.
886 // RAX: new object. 888 // RAX: new object.
887 // R10: number of context variables. 889 // R10: number of context variables.
888 __ movq(FieldAddress(RAX, Context::parent_offset()), R12); 890 // No generational barrier needed, since we are storing null.
891 __ StoreIntoObjectNoBarrier(RAX,
892 FieldAddress(RAX, Context::parent_offset()),
893 R12);
889 894
890 // Initialize the context variables. 895 // Initialize the context variables.
891 // RAX: new object. 896 // RAX: new object.
892 // R10: number of context variables. 897 // R10: number of context variables.
893 { 898 {
894 Label loop, entry; 899 Label loop, entry;
895 __ leaq(R13, FieldAddress(RAX, Context::variable_offset(0))); 900 __ leaq(R13, FieldAddress(RAX, Context::variable_offset(0)));
896 901
897 __ jmp(&entry, Assembler::kNearJump); 902 __ jmp(&entry, Assembler::kNearJump);
898 __ Bind(&loop); 903 __ Bind(&loop);
899 __ decq(R10); 904 __ decq(R10);
900 __ movq(Address(R13, R10, TIMES_8, 0), R12); 905 // No generational barrier needed, since we are storing null.
906 __ StoreIntoObjectNoBarrier(RAX,
907 Address(R13, R10, TIMES_8, 0),
908 R12);
901 __ Bind(&entry); 909 __ Bind(&entry);
902 __ cmpq(R10, Immediate(0)); 910 __ cmpq(R10, Immediate(0));
903 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); 911 __ j(NOT_EQUAL, &loop, Assembler::kNearJump);
904 } 912 }
905 913
906 // Done allocating and initializing the context. 914 // Done allocating and initializing the context.
907 // RAX: new object. 915 // RAX: new object.
908 __ ret(); 916 __ ret();
909 917
910 __ Bind(&slow_case); 918 __ Bind(&slow_case);
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1031 __ movq(R13, Immediate(heap->EndAddress(space))); 1039 __ movq(R13, Immediate(heap->EndAddress(space)));
1032 __ cmpq(RBX, Address(R13, 0)); 1040 __ cmpq(RBX, Address(R13, 0));
1033 if (FLAG_use_slow_path) { 1041 if (FLAG_use_slow_path) {
1034 __ jmp(&slow_case); 1042 __ jmp(&slow_case);
1035 } else { 1043 } else {
1036 __ j(ABOVE_EQUAL, &slow_case); 1044 __ j(ABOVE_EQUAL, &slow_case);
1037 } 1045 }
1038 __ movq(Address(RCX, 0), RBX); 1046 __ movq(Address(RCX, 0), RBX);
1039 __ UpdateAllocationStats(cls.id(), space); 1047 __ UpdateAllocationStats(cls.id(), space);
1040 1048
1041 // RAX: new object start. 1049 // RAX: new object start (untagged).
1042 // RBX: next object start. 1050 // RBX: next object start.
1043 // RDX: new object type arguments (if is_cls_parameterized). 1051 // RDX: new object type arguments (if is_cls_parameterized).
1044 // Set the tags. 1052 // Set the tags.
1045 uword tags = 0; 1053 uword tags = 0;
1046 tags = RawObject::SizeTag::update(instance_size, tags); 1054 tags = RawObject::SizeTag::update(instance_size, tags);
1047 ASSERT(cls.id() != kIllegalCid); 1055 ASSERT(cls.id() != kIllegalCid);
1048 tags = RawObject::ClassIdTag::update(cls.id(), tags); 1056 tags = RawObject::ClassIdTag::update(cls.id(), tags);
1049 __ movq(Address(RAX, Instance::tags_offset()), Immediate(tags)); 1057 __ movq(Address(RAX, Instance::tags_offset()), Immediate(tags));
1058 __ addq(RAX, Immediate(kHeapObjectTag));
1050 1059
1051 // Initialize the remaining words of the object. 1060 // Initialize the remaining words of the object.
1052 // RAX: new object start. 1061 // RAX: new object (tagged).
1053 // RBX: next object start. 1062 // RBX: next object start.
1054 // RDX: new object type arguments (if is_cls_parameterized). 1063 // RDX: new object type arguments (if is_cls_parameterized).
1055 // R12: raw null. 1064 // R12: raw null.
1056 // First try inlining the initialization without a loop. 1065 // First try inlining the initialization without a loop.
1057 if (instance_size < (kInlineInstanceSize * kWordSize)) { 1066 if (instance_size < (kInlineInstanceSize * kWordSize)) {
1058 // Check if the object contains any non-header fields. 1067 // Check if the object contains any non-header fields.
1059 // Small objects are initialized using a consecutive set of writes. 1068 // Small objects are initialized using a consecutive set of writes.
1060 for (intptr_t current_offset = Instance::NextFieldOffset(); 1069 for (intptr_t current_offset = Instance::NextFieldOffset();
1061 current_offset < instance_size; 1070 current_offset < instance_size;
1062 current_offset += kWordSize) { 1071 current_offset += kWordSize) {
1063 __ movq(Address(RAX, current_offset), R12); 1072 __ StoreIntoObjectNoBarrier(RAX,
1073 FieldAddress(RAX, current_offset),
1074 R12);
1064 } 1075 }
1065 } else { 1076 } else {
1066 __ leaq(RCX, Address(RAX, Instance::NextFieldOffset())); 1077 __ leaq(RCX, FieldAddress(RAX, Instance::NextFieldOffset()));
1067 // Loop until the whole object is initialized. 1078 // Loop until the whole object is initialized.
1068 // RAX: new object. 1079 // RAX: new object (tagged).
1069 // RBX: next object start. 1080 // RBX: next object start.
1070 // RCX: next word to be initialized. 1081 // RCX: next word to be initialized.
1071 // RDX: new object type arguments (if is_cls_parameterized). 1082 // RDX: new object type arguments (if is_cls_parameterized).
1072 Label init_loop; 1083 Label init_loop;
1073 Label done; 1084 Label done;
1074 __ Bind(&init_loop); 1085 __ Bind(&init_loop);
1075 __ cmpq(RCX, RBX); 1086 __ cmpq(RCX, RBX);
1076 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); 1087 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump);
1077 __ movq(Address(RCX, 0), R12); 1088 __ StoreIntoObjectNoBarrier(RAX, Address(RCX, 0), R12);
1078 __ addq(RCX, Immediate(kWordSize)); 1089 __ addq(RCX, Immediate(kWordSize));
1079 __ jmp(&init_loop, Assembler::kNearJump); 1090 __ jmp(&init_loop, Assembler::kNearJump);
1080 __ Bind(&done); 1091 __ Bind(&done);
1081 } 1092 }
1082 if (is_cls_parameterized) { 1093 if (is_cls_parameterized) {
1083 // RDX: new object type arguments. 1094 // RDX: new object type arguments.
1084 // Set the type arguments in the new object. 1095 // Set the type arguments in the new object.
1085 __ movq(Address(RAX, cls.type_arguments_field_offset()), RDX); 1096 intptr_t offset = cls.type_arguments_field_offset();
1097 __ StoreIntoObjectNoBarrier(RAX, FieldAddress(RAX, offset), RDX);
1086 } 1098 }
1087 // Done allocating and initializing the instance. 1099 // Done allocating and initializing the instance.
1088 // RAX: new object. 1100 // RAX: new object (tagged).
1089 __ addq(RAX, Immediate(kHeapObjectTag));
1090 __ ret(); 1101 __ ret();
1091 1102
1092 __ Bind(&slow_case); 1103 __ Bind(&slow_case);
1093 } 1104 }
1094 // If is_cls_parameterized: 1105 // If is_cls_parameterized:
1095 // RDX: new object type arguments. 1106 // RDX: new object type arguments.
1096 // Create a stub frame. 1107 // Create a stub frame.
1097 __ EnterStubFrame(true); // Uses PP to access class object. 1108 __ EnterStubFrame(true); // Uses PP to access class object.
1098 __ pushq(R12); // Setup space on stack for return value. 1109 __ pushq(R12); // Setup space on stack for return value.
1099 __ PushObject(cls, PP); // Push class of object to be allocated. 1110 __ PushObject(cls, PP); // Push class of object to be allocated.
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
1189 if (FLAG_throw_on_javascript_int_overflow) { 1200 if (FLAG_throw_on_javascript_int_overflow) {
1190 // The overflow check is more complex than implemented below. 1201 // The overflow check is more complex than implemented below.
1191 return; 1202 return;
1192 } 1203 }
1193 ASSERT(num_args == 2); 1204 ASSERT(num_args == 2);
1194 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Right 1205 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Right
1195 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left. 1206 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left.
1196 __ movq(R12, RCX); 1207 __ movq(R12, RCX);
1197 __ orq(R12, RAX); 1208 __ orq(R12, RAX);
1198 __ testq(R12, Immediate(kSmiTagMask)); 1209 __ testq(R12, Immediate(kSmiTagMask));
1199 __ j(NOT_ZERO, not_smi_or_overflow, Assembler::kNearJump); 1210 #if defined(DEBUG)
1211 const bool jump_length = Assembler::kFarJump;
1212 #else
1213 const bool jump_length = Assembler::kNearJump;
1214 #endif
1215 __ j(NOT_ZERO, not_smi_or_overflow, jump_length);
1200 switch (kind) { 1216 switch (kind) {
1201 case Token::kADD: { 1217 case Token::kADD: {
1202 __ addq(RAX, RCX); 1218 __ addq(RAX, RCX);
1203 __ j(OVERFLOW, not_smi_or_overflow, Assembler::kNearJump); 1219 __ j(OVERFLOW, not_smi_or_overflow, jump_length);
1204 break; 1220 break;
1205 } 1221 }
1206 case Token::kSUB: { 1222 case Token::kSUB: {
1207 __ subq(RAX, RCX); 1223 __ subq(RAX, RCX);
1208 __ j(OVERFLOW, not_smi_or_overflow, Assembler::kNearJump); 1224 __ j(OVERFLOW, not_smi_or_overflow, jump_length);
1209 break; 1225 break;
1210 } 1226 }
1211 case Token::kEQ: { 1227 case Token::kEQ: {
1212 Label done, is_true; 1228 Label done, is_true;
1213 __ cmpq(RAX, RCX); 1229 __ cmpq(RAX, RCX);
1214 __ j(EQUAL, &is_true, Assembler::kNearJump); 1230 __ j(EQUAL, &is_true, Assembler::kNearJump);
1215 __ LoadObject(RAX, Bool::False(), PP); 1231 __ LoadObject(RAX, Bool::False(), PP);
1216 __ jmp(&done, Assembler::kNearJump); 1232 __ jmp(&done, Assembler::kNearJump);
1217 __ Bind(&is_true); 1233 __ Bind(&is_true);
1218 __ LoadObject(RAX, Bool::True(), PP); 1234 __ LoadObject(RAX, Bool::True(), PP);
(...skipping 21 matching lines...) Expand all
1240 __ Stop("Incorrect IC data"); 1256 __ Stop("Incorrect IC data");
1241 __ Bind(&ok); 1257 __ Bind(&ok);
1242 #endif 1258 #endif
1243 1259
1244 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; 1260 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
1245 // Update counter. 1261 // Update counter.
1246 __ movq(R8, Address(R12, count_offset)); 1262 __ movq(R8, Address(R12, count_offset));
1247 __ addq(R8, Immediate(Smi::RawValue(1))); 1263 __ addq(R8, Immediate(Smi::RawValue(1)));
1248 __ movq(R9, Immediate(Smi::RawValue(Smi::kMaxValue))); 1264 __ movq(R9, Immediate(Smi::RawValue(Smi::kMaxValue)));
1249 __ cmovnoq(R9, R8); 1265 __ cmovnoq(R9, R8);
1250 __ movq(Address(R12, count_offset), R9); 1266 __ StoreIntoSmiField(Address(R12, count_offset), R9);
1251 1267
1252 __ ret(); 1268 __ ret();
1253 } 1269 }
1254 1270
1255 1271
1256 // Generate inline cache check for 'num_args'. 1272 // Generate inline cache check for 'num_args'.
1257 // RBX: Inline cache data object. 1273 // RBX: Inline cache data object.
1258 // TOS(0): return address 1274 // TOS(0): return address
1259 // Control flow: 1275 // Control flow:
1260 // - If receiver is null -> jump to IC miss. 1276 // - If receiver is null -> jump to IC miss.
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
1382 // R12: Pointer to an IC data check group. 1398 // R12: Pointer to an IC data check group.
1383 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize; 1399 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
1384 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize; 1400 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
1385 __ movq(RAX, Address(R12, target_offset)); 1401 __ movq(RAX, Address(R12, target_offset));
1386 1402
1387 // Update counter. 1403 // Update counter.
1388 __ movq(R8, Address(R12, count_offset)); 1404 __ movq(R8, Address(R12, count_offset));
1389 __ addq(R8, Immediate(Smi::RawValue(1))); 1405 __ addq(R8, Immediate(Smi::RawValue(1)));
1390 __ movq(R9, Immediate(Smi::RawValue(Smi::kMaxValue))); 1406 __ movq(R9, Immediate(Smi::RawValue(Smi::kMaxValue)));
1391 __ cmovnoq(R9, R8); 1407 __ cmovnoq(R9, R8);
1392 __ movq(Address(R12, count_offset), R9); 1408 __ StoreIntoSmiField(Address(R12, count_offset), R9);
1393 1409
1394 __ Bind(&call_target_function); 1410 __ Bind(&call_target_function);
1395 // RAX: Target function. 1411 // RAX: Target function.
1396 Label is_compiled; 1412 Label is_compiled;
1397 __ movq(RCX, FieldAddress(RAX, Function::instructions_offset())); 1413 __ movq(RCX, FieldAddress(RAX, Function::instructions_offset()));
1398 __ addq(RCX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); 1414 __ addq(RCX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
1399 __ jmp(RCX); 1415 __ jmp(RCX);
1400 1416
1401 __ Bind(&stepping); 1417 __ Bind(&stepping);
1402 __ EnterStubFrame(); 1418 __ EnterStubFrame();
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
1528 __ leaq(R12, FieldAddress(R12, Array::data_offset())); 1544 __ leaq(R12, FieldAddress(R12, Array::data_offset()));
1529 // R12: points directly to the first ic data array element. 1545 // R12: points directly to the first ic data array element.
1530 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize; 1546 const intptr_t target_offset = ICData::TargetIndexFor(0) * kWordSize;
1531 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize; 1547 const intptr_t count_offset = ICData::CountIndexFor(0) * kWordSize;
1532 1548
1533 // Increment count for this call. 1549 // Increment count for this call.
1534 __ movq(R8, Address(R12, count_offset)); 1550 __ movq(R8, Address(R12, count_offset));
1535 __ addq(R8, Immediate(Smi::RawValue(1))); 1551 __ addq(R8, Immediate(Smi::RawValue(1)));
1536 __ movq(R9, Immediate(Smi::RawValue(Smi::kMaxValue))); 1552 __ movq(R9, Immediate(Smi::RawValue(Smi::kMaxValue)));
1537 __ cmovnoq(R9, R8); 1553 __ cmovnoq(R9, R8);
1538 __ movq(Address(R12, count_offset), R9); 1554 __ StoreIntoSmiField(Address(R12, count_offset), R9);
1539 1555
1540 // Load arguments descriptor into R10. 1556 // Load arguments descriptor into R10.
1541 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset())); 1557 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset()));
1542 1558
1543 // Get function and call it, if possible. 1559 // Get function and call it, if possible.
1544 __ movq(RAX, Address(R12, target_offset)); 1560 __ movq(RAX, Address(R12, target_offset));
1545 __ movq(RCX, FieldAddress(RAX, Function::instructions_offset())); 1561 __ movq(RCX, FieldAddress(RAX, Function::instructions_offset()));
1546 // RCX: Target instructions. 1562 // RCX: Target instructions.
1547 __ addq(RCX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); 1563 __ addq(RCX, Immediate(Instructions::HeaderSize() - kHeapObjectTag));
1548 __ jmp(RCX); 1564 __ jmp(RCX);
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after
1951 1967
1952 __ movq(left, Address(RSP, 2 * kWordSize)); 1968 __ movq(left, Address(RSP, 2 * kWordSize));
1953 __ movq(right, Address(RSP, 1 * kWordSize)); 1969 __ movq(right, Address(RSP, 1 * kWordSize));
1954 GenerateIdenticalWithNumberCheckStub(assembler, left, right); 1970 GenerateIdenticalWithNumberCheckStub(assembler, left, right);
1955 __ ret(); 1971 __ ret();
1956 } 1972 }
1957 1973
1958 } // namespace dart 1974 } // namespace dart
1959 1975
1960 #endif // defined TARGET_ARCH_X64 1976 #endif // defined TARGET_ARCH_X64
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698