| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 static Register registers[] = { x0 }; | 210 static Register registers[] = { x0 }; |
| 211 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); | 211 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); |
| 212 descriptor->register_params_ = registers; | 212 descriptor->register_params_ = registers; |
| 213 descriptor->deoptimization_handler_ = | 213 descriptor->deoptimization_handler_ = |
| 214 FUNCTION_ADDR(CompareNilIC_Miss); | 214 FUNCTION_ADDR(CompareNilIC_Miss); |
| 215 descriptor->SetMissHandler( | 215 descriptor->SetMissHandler( |
| 216 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate)); | 216 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate)); |
| 217 } | 217 } |
| 218 | 218 |
| 219 | 219 |
| 220 void BinaryOpICStub::InitializeInterfaceDescriptor( | |
| 221 Isolate* isolate, | |
| 222 CodeStubInterfaceDescriptor* descriptor) { | |
| 223 // x1: left operand | |
| 224 // x0: right operand | |
| 225 static Register registers[] = { x1, x0 }; | |
| 226 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); | |
| 227 descriptor->register_params_ = registers; | |
| 228 descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss); | |
| 229 descriptor->SetMissHandler( | |
| 230 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate)); | |
| 231 } | |
| 232 | |
| 233 | |
| 234 static void InitializeArrayConstructorDescriptor( | 220 static void InitializeArrayConstructorDescriptor( |
| 235 Isolate* isolate, | 221 Isolate* isolate, |
| 236 CodeStubInterfaceDescriptor* descriptor, | 222 CodeStubInterfaceDescriptor* descriptor, |
| 237 int constant_stack_parameter_count) { | 223 int constant_stack_parameter_count) { |
| 238 // x1: function | 224 // x1: function |
| 239 // x2: type info cell with elements kind | 225 // x2: type info cell with elements kind |
| 240 // x0: number of arguments to the constructor function | 226 // x0: number of arguments to the constructor function |
| 241 static Register registers_variable_args[] = { x1, x2, x0 }; | 227 static Register registers_variable_args[] = { x1, x2, x0 }; |
| 242 static Register registers_no_args[] = { x1, x2 }; | 228 static Register registers_no_args[] = { x1, x2 }; |
| 243 | 229 |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 // x1: key | 353 // x1: key |
| 368 // x2: receiver | 354 // x2: receiver |
| 369 static Register registers[] = { x0, x3, x1, x2 }; | 355 static Register registers[] = { x0, x3, x1, x2 }; |
| 370 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); | 356 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); |
| 371 descriptor->register_params_ = registers; | 357 descriptor->register_params_ = registers; |
| 372 descriptor->deoptimization_handler_ = | 358 descriptor->deoptimization_handler_ = |
| 373 FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss); | 359 FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss); |
| 374 } | 360 } |
| 375 | 361 |
| 376 | 362 |
| 363 void BinaryOpICStub::InitializeInterfaceDescriptor( |
| 364 Isolate* isolate, |
| 365 CodeStubInterfaceDescriptor* descriptor) { |
| 366 // x1: left operand |
| 367 // x0: right operand |
| 368 static Register registers[] = { x1, x0 }; |
| 369 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); |
| 370 descriptor->register_params_ = registers; |
| 371 descriptor->deoptimization_handler_ = FUNCTION_ADDR(BinaryOpIC_Miss); |
| 372 descriptor->SetMissHandler( |
| 373 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate)); |
| 374 } |
| 375 |
| 376 |
| 377 void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor( |
| 378 Isolate* isolate, |
| 379 CodeStubInterfaceDescriptor* descriptor) { |
| 380 // x2: allocation site |
| 381 // x1: left operand |
| 382 // x0: right operand |
| 383 static Register registers[] = { x2, x1, x0 }; |
| 384 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); |
| 385 descriptor->register_params_ = registers; |
| 386 descriptor->deoptimization_handler_ = |
| 387 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); |
| 388 } |
| 389 |
| 390 |
| 377 void NewStringAddStub::InitializeInterfaceDescriptor( | 391 void NewStringAddStub::InitializeInterfaceDescriptor( |
| 378 Isolate* isolate, | 392 Isolate* isolate, |
| 379 CodeStubInterfaceDescriptor* descriptor) { | 393 CodeStubInterfaceDescriptor* descriptor) { |
| 380 // x1: left operand | 394 // x1: left operand |
| 381 // x0: right operand | 395 // x0: right operand |
| 382 static Register registers[] = { x1, x0 }; | 396 static Register registers[] = { x1, x0 }; |
| 383 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); | 397 descriptor->register_param_count_ = sizeof(registers) / sizeof(registers[0]); |
| 384 descriptor->register_params_ = registers; | 398 descriptor->register_params_ = registers; |
| 385 descriptor->deoptimization_handler_ = | 399 descriptor->deoptimization_handler_ = |
| 386 Runtime::FunctionForId(Runtime::kStringAdd)->entry; | 400 Runtime::FunctionForId(Runtime::kStringAdd)->entry; |
| (...skipping 638 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1025 | 1039 |
| 1026 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime( | 1040 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime( |
| 1027 Isolate* isolate) { | 1041 Isolate* isolate) { |
| 1028 StoreBufferOverflowStub stub1(kDontSaveFPRegs); | 1042 StoreBufferOverflowStub stub1(kDontSaveFPRegs); |
| 1029 stub1.GetCode(isolate); | 1043 stub1.GetCode(isolate); |
| 1030 StoreBufferOverflowStub stub2(kSaveFPRegs); | 1044 StoreBufferOverflowStub stub2(kSaveFPRegs); |
| 1031 stub2.GetCode(isolate); | 1045 stub2.GetCode(isolate); |
| 1032 } | 1046 } |
| 1033 | 1047 |
| 1034 | 1048 |
| 1035 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { | |
| 1036 // Untagged case: | |
| 1037 // Input: double in d0 | |
| 1038 // Result: double in d0 | |
| 1039 // | |
| 1040 // Tagged case: | |
| 1041 // Input: tagged value in jssp[0] | |
| 1042 // Result: tagged value in x0 | |
| 1043 | |
| 1044 const bool tagged = (argument_type_ == TAGGED); | |
| 1045 | |
| 1046 Label calculate; | |
| 1047 Label invalid_cache; | |
| 1048 Register scratch0 = x10; | |
| 1049 Register scratch1 = x11; | |
| 1050 Register cache_entry = x12; | |
| 1051 Register hash = x13; | |
| 1052 Register hash_w = hash.W(); | |
| 1053 Register input_double_bits = x14; | |
| 1054 Register input_tagged = x15; | |
| 1055 Register result_tagged = x0; | |
| 1056 FPRegister result_double = d0; | |
| 1057 FPRegister input_double = d0; | |
| 1058 | |
| 1059 // First, get the input as a double, in an integer register (so we can | |
| 1060 // calculate a hash). | |
| 1061 if (tagged) { | |
| 1062 Label input_not_smi, loaded; | |
| 1063 // Load argument and check if it is a smi. | |
| 1064 __ Pop(input_tagged); | |
| 1065 __ JumpIfNotSmi(input_tagged, &input_not_smi); | |
| 1066 | |
| 1067 // Input is a smi, so convert it to a double. | |
| 1068 __ SmiUntagToDouble(input_double, input_tagged); | |
| 1069 __ Fmov(input_double_bits, input_double); | |
| 1070 __ B(&loaded); | |
| 1071 | |
| 1072 __ Bind(&input_not_smi); | |
| 1073 // Check if input is a HeapNumber. | |
| 1074 __ JumpIfNotHeapNumber(input_tagged, &calculate); | |
| 1075 // The input is a HeapNumber. Load it into input_double_bits. | |
| 1076 __ Ldr(input_double_bits, | |
| 1077 FieldMemOperand(input_tagged, HeapNumber::kValueOffset)); | |
| 1078 | |
| 1079 __ Bind(&loaded); | |
| 1080 } else { | |
| 1081 // Get the integer representation of the double. | |
| 1082 __ Fmov(input_double_bits, input_double); | |
| 1083 } | |
| 1084 | |
| 1085 // Compute hash (the shifts are arithmetic): | |
| 1086 // h = (input_double_bits[31:0] ^ input_double_bits[63:32]); | |
| 1087 // h ^= h >> 16; | |
| 1088 // h ^= h >> 8; | |
| 1089 // h = h % cacheSize; | |
| 1090 __ Eor(hash, input_double_bits, Operand(input_double_bits, LSR, 32)); | |
| 1091 __ Eor(hash_w, hash_w, Operand(hash_w, ASR, 16)); | |
| 1092 __ Eor(hash_w, hash_w, Operand(hash_w, ASR, 8)); | |
| 1093 __ And(hash_w, hash_w, TranscendentalCache::SubCache::kCacheSize - 1); | |
| 1094 STATIC_ASSERT(IS_POWER_OF_TWO(TranscendentalCache::SubCache::kCacheSize)); | |
| 1095 | |
| 1096 // d0 input_double Double input value (if UNTAGGED). | |
| 1097 // x13(w13) hash(_w) TranscendentalCache::hash(input). | |
| 1098 // x14 input_double_bits Input value as double bits. | |
| 1099 // x15 input_tagged Tagged input value (if TAGGED). | |
| 1100 Isolate* isolate = masm->isolate(); | |
| 1101 ExternalReference cache_array = | |
| 1102 ExternalReference::transcendental_cache_array_address(isolate); | |
| 1103 int cache_array_index = | |
| 1104 type_ * sizeof(isolate->transcendental_cache()->caches_[0]); | |
| 1105 | |
| 1106 __ Mov(cache_entry, Operand(cache_array)); | |
| 1107 __ Ldr(cache_entry, MemOperand(cache_entry, cache_array_index)); | |
| 1108 | |
| 1109 // x12 cache_entry The address of the cache for type_. | |
| 1110 // If NULL, the cache hasn't been initialized yet, so go through runtime. | |
| 1111 __ Cbz(cache_entry, &invalid_cache); | |
| 1112 | |
| 1113 #ifdef DEBUG | |
| 1114 // Check that the layout of cache elements match expectations. | |
| 1115 { TranscendentalCache::SubCache::Element test_elem[2]; | |
| 1116 uintptr_t elem_start = reinterpret_cast<uintptr_t>(&test_elem[0]); | |
| 1117 uintptr_t elem2_start = reinterpret_cast<uintptr_t>(&test_elem[1]); | |
| 1118 uintptr_t elem_in0 = reinterpret_cast<uintptr_t>(&(test_elem[0].in[0])); | |
| 1119 uintptr_t elem_in1 = reinterpret_cast<uintptr_t>(&(test_elem[0].in[1])); | |
| 1120 uintptr_t elem_out = reinterpret_cast<uintptr_t>(&(test_elem[0].output)); | |
| 1121 CHECK_EQ(16, elem2_start - elem_start); // Two uint_32s and a pointer. | |
| 1122 CHECK_EQ(0, elem_in0 - elem_start); | |
| 1123 CHECK_EQ(kIntSize, elem_in1 - elem_start); | |
| 1124 CHECK_EQ(2 * kIntSize, elem_out - elem_start); | |
| 1125 } | |
| 1126 #endif | |
| 1127 | |
| 1128 // The (candidate) cached element is at cache[hash*16]. | |
| 1129 __ Add(cache_entry, cache_entry, Operand(hash, LSL, 4)); | |
| 1130 __ Ldp(scratch0, result_tagged, MemOperand(cache_entry)); | |
| 1131 __ Cmp(scratch0, input_double_bits); | |
| 1132 __ B(&calculate, ne); | |
| 1133 | |
| 1134 // Cache hit: Load the result and return. | |
| 1135 | |
| 1136 __ IncrementCounter(isolate->counters()->transcendental_cache_hit(), 1, | |
| 1137 scratch0, scratch1); | |
| 1138 if (!tagged) { | |
| 1139 // result_tagged now already holds the tagged result from the cache, but we | |
| 1140 // need to untag it for the untagged case. | |
| 1141 __ Ldr(result_double, FieldMemOperand(result_tagged, | |
| 1142 HeapNumber::kValueOffset)); | |
| 1143 } | |
| 1144 __ Ret(); | |
| 1145 | |
| 1146 // Cache miss: Calculate the result. | |
| 1147 | |
| 1148 __ Bind(&calculate); | |
| 1149 __ IncrementCounter(isolate->counters()->transcendental_cache_miss(), 1, | |
| 1150 scratch0, scratch1); | |
| 1151 if (tagged) { | |
| 1152 __ Bind(&invalid_cache); | |
| 1153 __ Push(input_tagged); | |
| 1154 ExternalReference runtime_function = ExternalReference(RuntimeFunction(), | |
| 1155 masm->isolate()); | |
| 1156 __ TailCallExternalReference(runtime_function, 1, 1); | |
| 1157 } else { | |
| 1158 Label gc_required; | |
| 1159 Label calculation_and_gc_required; | |
| 1160 | |
| 1161 // Call a C function to calculate the result, then update the cache. | |
| 1162 // The following caller-saved registers need to be preserved for the call: | |
| 1163 // x12 cache_entry The address of the cache for type_. | |
| 1164 // x14 input_double_bits The bit representation of the input. | |
| 1165 // lr The return address of the stub. | |
| 1166 __ Push(cache_entry, input_double_bits, lr); | |
| 1167 ASSERT(input_double.Is(d0)); | |
| 1168 { AllowExternalCallThatCantCauseGC scope(masm); | |
| 1169 __ CallCFunction(CFunction(isolate), 0, 1); | |
| 1170 } | |
| 1171 ASSERT(result_double.Is(d0)); | |
| 1172 __ Pop(lr, input_double_bits, cache_entry); | |
| 1173 | |
| 1174 // Try to update the cache. | |
| 1175 __ AllocateHeapNumber(result_tagged, &gc_required, scratch0, scratch1); | |
| 1176 __ Str(result_double, FieldMemOperand(result_tagged, | |
| 1177 HeapNumber::kValueOffset)); | |
| 1178 __ Stp(input_double_bits, result_tagged, MemOperand(cache_entry)); | |
| 1179 __ Ret(); | |
| 1180 | |
| 1181 | |
| 1182 __ Bind(&invalid_cache); | |
| 1183 // Handle an invalid (uninitialized) cache by calling the runtime. | |
| 1184 // d0 input_double Double input value (if UNTAGGED). | |
| 1185 __ AllocateHeapNumber(result_tagged, &calculation_and_gc_required, | |
| 1186 scratch0, scratch1); | |
| 1187 __ Str(input_double, FieldMemOperand(result_tagged, | |
| 1188 HeapNumber::kValueOffset)); | |
| 1189 { FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1190 __ Push(result_tagged); | |
| 1191 __ CallRuntime(RuntimeFunction(), 1); | |
| 1192 } | |
| 1193 __ Ldr(result_double, FieldMemOperand(result_tagged, | |
| 1194 HeapNumber::kValueOffset)); | |
| 1195 __ Ret(); | |
| 1196 | |
| 1197 | |
| 1198 __ Bind(&calculation_and_gc_required); | |
| 1199 // Call C function to calculate the result and answer directly without | |
| 1200 // updating the cache. | |
| 1201 ASSERT(input_double.Is(d0)); | |
| 1202 { AllowExternalCallThatCantCauseGC scope(masm); | |
| 1203 __ CallCFunction(CFunction(isolate), 0, 1); | |
| 1204 } | |
| 1205 ASSERT(result_double.Is(d0)); | |
| 1206 | |
| 1207 | |
| 1208 // We got here because an allocation failed. Trigger a scavenging GC so that | |
| 1209 // future allocations will succeed. | |
| 1210 __ Bind(&gc_required); | |
| 1211 __ Push(result_double); | |
| 1212 { FrameScope scope(masm, StackFrame::INTERNAL); | |
| 1213 // Allocate an aligned object larger than a HeapNumber. | |
| 1214 int alloc_size = 2 * kPointerSize; | |
| 1215 ASSERT(alloc_size >= HeapNumber::kSize); | |
| 1216 __ Mov(scratch0, Operand(Smi::FromInt(alloc_size))); | |
| 1217 __ Push(scratch0); | |
| 1218 __ CallRuntime(Runtime::kAllocateInNewSpace, 1); | |
| 1219 } | |
| 1220 __ Pop(result_double); | |
| 1221 __ Ret(); | |
| 1222 } | |
| 1223 } | |
| 1224 | |
| 1225 | |
| 1226 ExternalReference TranscendentalCacheStub::CFunction(Isolate* isolate) { | |
| 1227 switch (type_) { | |
| 1228 // Add more cases when necessary. | |
| 1229 default: | |
| 1230 // There's no NULL ExternalReference, so fall into an existing case to | |
| 1231 // avoid compiler warnings about not having a return value. | |
| 1232 UNIMPLEMENTED(); | |
| 1233 case TranscendentalCache::LOG: | |
| 1234 return ExternalReference::math_log_double_function(isolate); | |
| 1235 } | |
| 1236 } | |
| 1237 | |
| 1238 | |
| 1239 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { | |
| 1240 switch (type_) { | |
| 1241 // Add more cases when necessary. | |
| 1242 case TranscendentalCache::LOG: return Runtime::kMath_log; | |
| 1243 default: | |
| 1244 UNIMPLEMENTED(); | |
| 1245 return Runtime::kAbort; | |
| 1246 } | |
| 1247 } | |
| 1248 | |
| 1249 | |
| 1250 void MathPowStub::Generate(MacroAssembler* masm) { | 1049 void MathPowStub::Generate(MacroAssembler* masm) { |
| 1251 // Stack on entry: | 1050 // Stack on entry: |
| 1252 // jssp[0]: Exponent (as a tagged value). | 1051 // jssp[0]: Exponent (as a tagged value). |
| 1253 // jssp[1]: Base (as a tagged value). | 1052 // jssp[1]: Base (as a tagged value). |
| 1254 // | 1053 // |
| 1255 // The (tagged) result will be returned in x0, as a heap number. | 1054 // The (tagged) result will be returned in x0, as a heap number. |
| 1256 | 1055 |
| 1257 Register result_tagged = x0; | 1056 Register result_tagged = x0; |
| 1258 Register base_tagged = x10; | 1057 Register base_tagged = x10; |
| 1259 Register exponent_tagged = x11; | 1058 Register exponent_tagged = x11; |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1503 // It is important that the following stubs are generated in this order | 1302 // It is important that the following stubs are generated in this order |
| 1504 // because pregenerated stubs can only call other pregenerated stubs. | 1303 // because pregenerated stubs can only call other pregenerated stubs. |
| 1505 // RecordWriteStub uses StoreBufferOverflowStub, which in turn uses | 1304 // RecordWriteStub uses StoreBufferOverflowStub, which in turn uses |
| 1506 // CEntryStub. | 1305 // CEntryStub. |
| 1507 CEntryStub::GenerateAheadOfTime(isolate); | 1306 CEntryStub::GenerateAheadOfTime(isolate); |
| 1508 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); | 1307 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate); |
| 1509 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); | 1308 StubFailureTrampolineStub::GenerateAheadOfTime(isolate); |
| 1510 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); | 1309 ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate); |
| 1511 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); | 1310 CreateAllocationSiteStub::GenerateAheadOfTime(isolate); |
| 1512 BinaryOpICStub::GenerateAheadOfTime(isolate); | 1311 BinaryOpICStub::GenerateAheadOfTime(isolate); |
| 1312 BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate); |
| 1513 } | 1313 } |
| 1514 | 1314 |
| 1515 | 1315 |
| 1516 void CodeStub::GenerateFPStubs(Isolate* isolate) { | 1316 void CodeStub::GenerateFPStubs(Isolate* isolate) { |
| 1517 // Floating-point code doesn't get special handling in A64, so there's | 1317 // Floating-point code doesn't get special handling in A64, so there's |
| 1518 // nothing to do here. | 1318 // nothing to do here. |
| 1519 USE(isolate); | 1319 USE(isolate); |
| 1520 } | 1320 } |
| 1521 | 1321 |
| 1522 | 1322 |
| (...skipping 3258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4781 // sp[0] = right string | 4581 // sp[0] = right string |
| 4782 // sp[8] = left string. | 4582 // sp[8] = left string. |
| 4783 __ Push(left, right); | 4583 __ Push(left, right); |
| 4784 | 4584 |
| 4785 // Call the runtime. | 4585 // Call the runtime. |
| 4786 // Returns -1 (less), 0 (equal), or 1 (greater) tagged as a small integer. | 4586 // Returns -1 (less), 0 (equal), or 1 (greater) tagged as a small integer. |
| 4787 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 4587 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 4788 } | 4588 } |
| 4789 | 4589 |
| 4790 | 4590 |
| 4591 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { |
| 4592 // ----------- S t a t e ------------- |
| 4593 // -- x1 : left |
| 4594 // -- x0 : right |
| 4595 // -- lr : return address |
| 4596 // ----------------------------------- |
| 4597 Isolate* isolate = masm->isolate(); |
| 4598 |
| 4599 // Load x2 with the allocation site. We stick an undefined dummy value here |
| 4600 // and replace it with the real allocation site later when we instantiate this |
| 4601 // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate(). |
| 4602 __ LoadObject(x2, handle(isolate->heap()->undefined_value())); |
| 4603 |
| 4604 // Make sure that we actually patched the allocation site. |
| 4605 if (FLAG_debug_code) { |
| 4606 __ AssertNotSmi(x2, kExpectedAllocationSite); |
| 4607 __ Ldr(x10, FieldMemOperand(x2, HeapObject::kMapOffset)); |
| 4608 __ AssertRegisterIsRoot(x10, Heap::kAllocationSiteMapRootIndex, |
| 4609 kExpectedAllocationSite); |
| 4610 } |
| 4611 |
| 4612 // Tail call into the stub that handles binary operations with allocation |
| 4613 // sites. |
| 4614 BinaryOpWithAllocationSiteStub stub(state_); |
| 4615 __ TailCallStub(&stub); |
| 4616 } |
| 4617 |
| 4618 |
| 4791 void StringAddStub::Generate(MacroAssembler* masm) { | 4619 void StringAddStub::Generate(MacroAssembler* masm) { |
| 4792 Label call_runtime, call_builtin; | 4620 Label call_runtime, call_builtin; |
| 4793 Builtins::JavaScript builtin_id = Builtins::ADD; | 4621 Builtins::JavaScript builtin_id = Builtins::ADD; |
| 4794 | 4622 |
| 4795 Counters* counters = masm->isolate()->counters(); | 4623 Counters* counters = masm->isolate()->counters(); |
| 4796 | 4624 |
| 4797 // Stack on entry: | 4625 // Stack on entry: |
| 4798 // sp[0]: second argument (right). | 4626 // sp[0]: second argument (right). |
| 4799 // sp[8]: first argument (left). | 4627 // sp[8]: first argument (left). |
| 4800 | 4628 |
| (...skipping 1331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6132 __ Bind(&fast_elements_case); | 5960 __ Bind(&fast_elements_case); |
| 6133 GenerateCase(masm, FAST_ELEMENTS); | 5961 GenerateCase(masm, FAST_ELEMENTS); |
| 6134 } | 5962 } |
| 6135 | 5963 |
| 6136 | 5964 |
| 6137 #undef __ | 5965 #undef __ |
| 6138 | 5966 |
| 6139 } } // namespace v8::internal | 5967 } } // namespace v8::internal |
| 6140 | 5968 |
| 6141 #endif // V8_TARGET_ARCH_A64 | 5969 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |