| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 21 matching lines...) Expand all Loading... |
| 32 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
| 33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
| 34 #include "codegen.h" | 34 #include "codegen.h" |
| 35 #include "regexp-macro-assembler.h" | 35 #include "regexp-macro-assembler.h" |
| 36 #include "stub-cache.h" | 36 #include "stub-cache.h" |
| 37 | 37 |
| 38 namespace v8 { | 38 namespace v8 { |
| 39 namespace internal { | 39 namespace internal { |
| 40 | 40 |
| 41 | 41 |
| 42 void ToNumberStub::InitializeInterfaceDescriptor( |
| 43 Isolate* isolate, |
| 44 CodeStubInterfaceDescriptor* descriptor) { |
| 45 static Register registers[] = { a0 }; |
| 46 descriptor->register_param_count_ = 1; |
| 47 descriptor->register_params_ = registers; |
| 48 descriptor->deoptimization_handler_ = NULL; |
| 49 } |
| 50 |
| 51 |
| 42 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor( | 52 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor( |
| 43 Isolate* isolate, | 53 Isolate* isolate, |
| 44 CodeStubInterfaceDescriptor* descriptor) { | 54 CodeStubInterfaceDescriptor* descriptor) { |
| 45 static Register registers[] = { a3, a2, a1 }; | 55 static Register registers[] = { a3, a2, a1 }; |
| 46 descriptor->register_param_count_ = 3; | 56 descriptor->register_param_count_ = 3; |
| 47 descriptor->register_params_ = registers; | 57 descriptor->register_params_ = registers; |
| 48 descriptor->deoptimization_handler_ = | 58 descriptor->deoptimization_handler_ = |
| 49 Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry; | 59 Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry; |
| 50 } | 60 } |
| 51 | 61 |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 Isolate* isolate, | 262 Isolate* isolate, |
| 253 CodeStubInterfaceDescriptor* descriptor) { | 263 CodeStubInterfaceDescriptor* descriptor) { |
| 254 static Register registers[] = { a1, a2, a0 }; | 264 static Register registers[] = { a1, a2, a0 }; |
| 255 descriptor->register_param_count_ = 3; | 265 descriptor->register_param_count_ = 3; |
| 256 descriptor->register_params_ = registers; | 266 descriptor->register_params_ = registers; |
| 257 descriptor->deoptimization_handler_ = | 267 descriptor->deoptimization_handler_ = |
| 258 FUNCTION_ADDR(StoreIC_MissFromStubFailure); | 268 FUNCTION_ADDR(StoreIC_MissFromStubFailure); |
| 259 } | 269 } |
| 260 | 270 |
| 261 | 271 |
| 272 void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor( |
| 273 Isolate* isolate, |
| 274 CodeStubInterfaceDescriptor* descriptor) { |
| 275 static Register registers[] = { a0, a3, a1, a2 }; |
| 276 descriptor->register_param_count_ = 4; |
| 277 descriptor->register_params_ = registers; |
| 278 descriptor->deoptimization_handler_ = |
| 279 FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss); |
| 280 } |
| 281 |
| 282 |
| 262 #define __ ACCESS_MASM(masm) | 283 #define __ ACCESS_MASM(masm) |
| 263 | 284 |
| 264 | 285 |
| 265 static void EmitIdenticalObjectComparison(MacroAssembler* masm, | 286 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
| 266 Label* slow, | 287 Label* slow, |
| 267 Condition cc); | 288 Condition cc); |
| 268 static void EmitSmiNonsmiComparison(MacroAssembler* masm, | 289 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
| 269 Register lhs, | 290 Register lhs, |
| 270 Register rhs, | 291 Register rhs, |
| 271 Label* rhs_not_nan, | 292 Label* rhs_not_nan, |
| 272 Label* slow, | 293 Label* slow, |
| 273 bool strict); | 294 bool strict); |
| 274 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, | 295 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, |
| 275 Register lhs, | 296 Register lhs, |
| 276 Register rhs); | 297 Register rhs); |
| 277 | 298 |
| 278 | 299 |
| 279 // Check if the operand is a heap number. | |
| 280 static void EmitCheckForHeapNumber(MacroAssembler* masm, Register operand, | |
| 281 Register scratch1, Register scratch2, | |
| 282 Label* not_a_heap_number) { | |
| 283 __ lw(scratch1, FieldMemOperand(operand, HeapObject::kMapOffset)); | |
| 284 __ LoadRoot(scratch2, Heap::kHeapNumberMapRootIndex); | |
| 285 __ Branch(not_a_heap_number, ne, scratch1, Operand(scratch2)); | |
| 286 } | |
| 287 | |
| 288 | |
| 289 void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { | 300 void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { |
| 290 // Update the static counter each time a new code stub is generated. | 301 // Update the static counter each time a new code stub is generated. |
| 291 Isolate* isolate = masm->isolate(); | 302 Isolate* isolate = masm->isolate(); |
| 292 isolate->counters()->code_stubs()->Increment(); | 303 isolate->counters()->code_stubs()->Increment(); |
| 293 | 304 |
| 294 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate); | 305 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate); |
| 295 int param_count = descriptor->register_param_count_; | 306 int param_count = descriptor->register_param_count_; |
| 296 { | 307 { |
| 297 // Call the runtime system in a fresh internal frame. | 308 // Call the runtime system in a fresh internal frame. |
| 298 FrameScope scope(masm, StackFrame::INTERNAL); | 309 FrameScope scope(masm, StackFrame::INTERNAL); |
| 299 ASSERT(descriptor->register_param_count_ == 0 || | 310 ASSERT(descriptor->register_param_count_ == 0 || |
| 300 a0.is(descriptor->register_params_[param_count - 1])); | 311 a0.is(descriptor->register_params_[param_count - 1])); |
| 301 // Push arguments | 312 // Push arguments |
| 302 for (int i = 0; i < param_count; ++i) { | 313 for (int i = 0; i < param_count; ++i) { |
| 303 __ push(descriptor->register_params_[i]); | 314 __ push(descriptor->register_params_[i]); |
| 304 } | 315 } |
| 305 ExternalReference miss = descriptor->miss_handler(); | 316 ExternalReference miss = descriptor->miss_handler(); |
| 306 __ CallExternalReference(miss, descriptor->register_param_count_); | 317 __ CallExternalReference(miss, descriptor->register_param_count_); |
| 307 } | 318 } |
| 308 | 319 |
| 309 __ Ret(); | 320 __ Ret(); |
| 310 } | 321 } |
| 311 | 322 |
| 312 | 323 |
| 313 void ToNumberStub::Generate(MacroAssembler* masm) { | |
| 314 // The ToNumber stub takes one argument in a0. | |
| 315 Label check_heap_number, call_builtin; | |
| 316 __ JumpIfNotSmi(a0, &check_heap_number); | |
| 317 __ Ret(USE_DELAY_SLOT); | |
| 318 __ mov(v0, a0); | |
| 319 | |
| 320 __ bind(&check_heap_number); | |
| 321 EmitCheckForHeapNumber(masm, a0, a1, t0, &call_builtin); | |
| 322 __ Ret(USE_DELAY_SLOT); | |
| 323 __ mov(v0, a0); | |
| 324 | |
| 325 __ bind(&call_builtin); | |
| 326 __ push(a0); | |
| 327 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); | |
| 328 } | |
| 329 | |
| 330 | |
| 331 void FastNewClosureStub::Generate(MacroAssembler* masm) { | 324 void FastNewClosureStub::Generate(MacroAssembler* masm) { |
| 332 // Create a new closure from the given function info in new | 325 // Create a new closure from the given function info in new |
| 333 // space. Set the context to the current context in cp. | 326 // space. Set the context to the current context in cp. |
| 334 Counters* counters = masm->isolate()->counters(); | 327 Counters* counters = masm->isolate()->counters(); |
| 335 | 328 |
| 336 Label gc; | 329 Label gc; |
| 337 | 330 |
| 338 // Pop the function info from the stack. | 331 // Pop the function info from the stack. |
| 339 __ pop(a3); | 332 __ pop(a3); |
| 340 | 333 |
| (...skipping 866 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1207 __ Branch(&return_not_equal, eq, a2, Operand(ODDBALL_TYPE)); | 1200 __ Branch(&return_not_equal, eq, a2, Operand(ODDBALL_TYPE)); |
| 1208 | 1201 |
| 1209 __ GetObjectType(rhs, a3, a3); | 1202 __ GetObjectType(rhs, a3, a3); |
| 1210 __ Branch(&return_not_equal, greater, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); | 1203 __ Branch(&return_not_equal, greater, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 1211 | 1204 |
| 1212 // Check for oddballs: true, false, null, undefined. | 1205 // Check for oddballs: true, false, null, undefined. |
| 1213 __ Branch(&return_not_equal, eq, a3, Operand(ODDBALL_TYPE)); | 1206 __ Branch(&return_not_equal, eq, a3, Operand(ODDBALL_TYPE)); |
| 1214 | 1207 |
| 1215 // Now that we have the types we might as well check for | 1208 // Now that we have the types we might as well check for |
| 1216 // internalized-internalized. | 1209 // internalized-internalized. |
| 1217 Label not_internalized; | 1210 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
| 1218 STATIC_ASSERT(kInternalizedTag != 0); | 1211 __ Or(a2, a2, Operand(a3)); |
| 1219 __ And(t2, a2, Operand(kIsNotStringMask | kIsInternalizedMask)); | 1212 __ And(at, a2, Operand(kIsNotStringMask | kIsNotInternalizedMask)); |
| 1220 __ Branch(¬_internalized, ne, t2, | 1213 __ Branch(&return_not_equal, eq, at, Operand(zero_reg)); |
| 1221 Operand(kInternalizedTag | kStringTag)); | |
| 1222 | |
| 1223 __ And(a3, a3, Operand(kIsNotStringMask | kIsInternalizedMask)); | |
| 1224 __ Branch(&return_not_equal, eq, a3, | |
| 1225 Operand(kInternalizedTag | kStringTag)); | |
| 1226 | |
| 1227 __ bind(¬_internalized); | |
| 1228 } | 1214 } |
| 1229 | 1215 |
| 1230 | 1216 |
| 1231 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, | 1217 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, |
| 1232 Register lhs, | 1218 Register lhs, |
| 1233 Register rhs, | 1219 Register rhs, |
| 1234 Label* both_loaded_as_doubles, | 1220 Label* both_loaded_as_doubles, |
| 1235 Label* not_heap_numbers, | 1221 Label* not_heap_numbers, |
| 1236 Label* slow) { | 1222 Label* slow) { |
| 1237 __ GetObjectType(lhs, a3, a2); | 1223 __ GetObjectType(lhs, a3, a2); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1253 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm, | 1239 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm, |
| 1254 Register lhs, | 1240 Register lhs, |
| 1255 Register rhs, | 1241 Register rhs, |
| 1256 Label* possible_strings, | 1242 Label* possible_strings, |
| 1257 Label* not_both_strings) { | 1243 Label* not_both_strings) { |
| 1258 ASSERT((lhs.is(a0) && rhs.is(a1)) || | 1244 ASSERT((lhs.is(a0) && rhs.is(a1)) || |
| 1259 (lhs.is(a1) && rhs.is(a0))); | 1245 (lhs.is(a1) && rhs.is(a0))); |
| 1260 | 1246 |
| 1261 // a2 is object type of rhs. | 1247 // a2 is object type of rhs. |
| 1262 Label object_test; | 1248 Label object_test; |
| 1263 STATIC_ASSERT(kInternalizedTag != 0); | 1249 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
| 1264 __ And(at, a2, Operand(kIsNotStringMask)); | 1250 __ And(at, a2, Operand(kIsNotStringMask)); |
| 1265 __ Branch(&object_test, ne, at, Operand(zero_reg)); | 1251 __ Branch(&object_test, ne, at, Operand(zero_reg)); |
| 1266 __ And(at, a2, Operand(kIsInternalizedMask)); | 1252 __ And(at, a2, Operand(kIsNotInternalizedMask)); |
| 1267 __ Branch(possible_strings, eq, at, Operand(zero_reg)); | 1253 __ Branch(possible_strings, ne, at, Operand(zero_reg)); |
| 1268 __ GetObjectType(rhs, a3, a3); | 1254 __ GetObjectType(rhs, a3, a3); |
| 1269 __ Branch(not_both_strings, ge, a3, Operand(FIRST_NONSTRING_TYPE)); | 1255 __ Branch(not_both_strings, ge, a3, Operand(FIRST_NONSTRING_TYPE)); |
| 1270 __ And(at, a3, Operand(kIsInternalizedMask)); | 1256 __ And(at, a3, Operand(kIsNotInternalizedMask)); |
| 1271 __ Branch(possible_strings, eq, at, Operand(zero_reg)); | 1257 __ Branch(possible_strings, ne, at, Operand(zero_reg)); |
| 1272 | 1258 |
| 1273 // Both are internalized strings. We already checked they weren't the same | 1259 // Both are internalized strings. We already checked they weren't the same |
| 1274 // pointer so they are not equal. | 1260 // pointer so they are not equal. |
| 1275 __ Ret(USE_DELAY_SLOT); | 1261 __ Ret(USE_DELAY_SLOT); |
| 1276 __ li(v0, Operand(1)); // Non-zero indicates not equal. | 1262 __ li(v0, Operand(1)); // Non-zero indicates not equal. |
| 1277 | 1263 |
| 1278 __ bind(&object_test); | 1264 __ bind(&object_test); |
| 1279 __ Branch(not_both_strings, lt, a2, Operand(FIRST_SPEC_OBJECT_TYPE)); | 1265 __ Branch(not_both_strings, lt, a2, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 1280 __ GetObjectType(rhs, a2, a3); | 1266 __ GetObjectType(rhs, a2, a3); |
| 1281 __ Branch(not_both_strings, lt, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); | 1267 __ Branch(not_both_strings, lt, a3, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1292 __ xori(v0, a0, 1 << Map::kIsUndetectable); | 1278 __ xori(v0, a0, 1 << Map::kIsUndetectable); |
| 1293 } | 1279 } |
| 1294 | 1280 |
| 1295 | 1281 |
| 1296 void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, | 1282 void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, |
| 1297 Register object, | 1283 Register object, |
| 1298 Register result, | 1284 Register result, |
| 1299 Register scratch1, | 1285 Register scratch1, |
| 1300 Register scratch2, | 1286 Register scratch2, |
| 1301 Register scratch3, | 1287 Register scratch3, |
| 1302 bool object_is_smi, | |
| 1303 Label* not_found) { | 1288 Label* not_found) { |
| 1304 // Use of registers. Register result is used as a temporary. | 1289 // Use of registers. Register result is used as a temporary. |
| 1305 Register number_string_cache = result; | 1290 Register number_string_cache = result; |
| 1306 Register mask = scratch3; | 1291 Register mask = scratch3; |
| 1307 | 1292 |
| 1308 // Load the number string cache. | 1293 // Load the number string cache. |
| 1309 __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex); | 1294 __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex); |
| 1310 | 1295 |
| 1311 // Make the hash mask from the length of the number string cache. It | 1296 // Make the hash mask from the length of the number string cache. It |
| 1312 // contains two elements (number and string) for each cache entry. | 1297 // contains two elements (number and string) for each cache entry. |
| 1313 __ lw(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset)); | 1298 __ lw(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset)); |
| 1314 // Divide length by two (length is a smi). | 1299 // Divide length by two (length is a smi). |
| 1315 __ sra(mask, mask, kSmiTagSize + 1); | 1300 __ sra(mask, mask, kSmiTagSize + 1); |
| 1316 __ Addu(mask, mask, -1); // Make mask. | 1301 __ Addu(mask, mask, -1); // Make mask. |
| 1317 | 1302 |
| 1318 // Calculate the entry in the number string cache. The hash value in the | 1303 // Calculate the entry in the number string cache. The hash value in the |
| 1319 // number string cache for smis is just the smi value, and the hash for | 1304 // number string cache for smis is just the smi value, and the hash for |
| 1320 // doubles is the xor of the upper and lower words. See | 1305 // doubles is the xor of the upper and lower words. See |
| 1321 // Heap::GetNumberStringCache. | 1306 // Heap::GetNumberStringCache. |
| 1322 Isolate* isolate = masm->isolate(); | 1307 Isolate* isolate = masm->isolate(); |
| 1323 Label is_smi; | 1308 Label is_smi; |
| 1324 Label load_result_from_cache; | 1309 Label load_result_from_cache; |
| 1325 if (!object_is_smi) { | 1310 __ JumpIfSmi(object, &is_smi); |
| 1326 __ JumpIfSmi(object, &is_smi); | 1311 __ CheckMap(object, |
| 1327 __ CheckMap(object, | 1312 scratch1, |
| 1328 scratch1, | 1313 Heap::kHeapNumberMapRootIndex, |
| 1329 Heap::kHeapNumberMapRootIndex, | 1314 not_found, |
| 1330 not_found, | 1315 DONT_DO_SMI_CHECK); |
| 1331 DONT_DO_SMI_CHECK); | |
| 1332 | 1316 |
| 1333 STATIC_ASSERT(8 == kDoubleSize); | 1317 STATIC_ASSERT(8 == kDoubleSize); |
| 1334 __ Addu(scratch1, | 1318 __ Addu(scratch1, |
| 1335 object, | 1319 object, |
| 1336 Operand(HeapNumber::kValueOffset - kHeapObjectTag)); | 1320 Operand(HeapNumber::kValueOffset - kHeapObjectTag)); |
| 1337 __ lw(scratch2, MemOperand(scratch1, kPointerSize)); | 1321 __ lw(scratch2, MemOperand(scratch1, kPointerSize)); |
| 1338 __ lw(scratch1, MemOperand(scratch1, 0)); | 1322 __ lw(scratch1, MemOperand(scratch1, 0)); |
| 1339 __ Xor(scratch1, scratch1, Operand(scratch2)); | 1323 __ Xor(scratch1, scratch1, Operand(scratch2)); |
| 1340 __ And(scratch1, scratch1, Operand(mask)); | 1324 __ And(scratch1, scratch1, Operand(mask)); |
| 1341 | 1325 |
| 1342 // Calculate address of entry in string cache: each entry consists | 1326 // Calculate address of entry in string cache: each entry consists |
| 1343 // of two pointer sized fields. | 1327 // of two pointer sized fields. |
| 1344 __ sll(scratch1, scratch1, kPointerSizeLog2 + 1); | 1328 __ sll(scratch1, scratch1, kPointerSizeLog2 + 1); |
| 1345 __ Addu(scratch1, number_string_cache, scratch1); | 1329 __ Addu(scratch1, number_string_cache, scratch1); |
| 1346 | 1330 |
| 1347 Register probe = mask; | 1331 Register probe = mask; |
| 1348 __ lw(probe, | 1332 __ lw(probe, |
| 1349 FieldMemOperand(scratch1, FixedArray::kHeaderSize)); | 1333 FieldMemOperand(scratch1, FixedArray::kHeaderSize)); |
| 1350 __ JumpIfSmi(probe, not_found); | 1334 __ JumpIfSmi(probe, not_found); |
| 1351 __ ldc1(f12, FieldMemOperand(object, HeapNumber::kValueOffset)); | 1335 __ ldc1(f12, FieldMemOperand(object, HeapNumber::kValueOffset)); |
| 1352 __ ldc1(f14, FieldMemOperand(probe, HeapNumber::kValueOffset)); | 1336 __ ldc1(f14, FieldMemOperand(probe, HeapNumber::kValueOffset)); |
| 1353 __ BranchF(&load_result_from_cache, NULL, eq, f12, f14); | 1337 __ BranchF(&load_result_from_cache, NULL, eq, f12, f14); |
| 1354 __ Branch(not_found); | 1338 __ Branch(not_found); |
| 1355 } | |
| 1356 | 1339 |
| 1357 __ bind(&is_smi); | 1340 __ bind(&is_smi); |
| 1358 Register scratch = scratch1; | 1341 Register scratch = scratch1; |
| 1359 __ sra(scratch, object, 1); // Shift away the tag. | 1342 __ sra(scratch, object, 1); // Shift away the tag. |
| 1360 __ And(scratch, mask, Operand(scratch)); | 1343 __ And(scratch, mask, Operand(scratch)); |
| 1361 | 1344 |
| 1362 // Calculate address of entry in string cache: each entry consists | 1345 // Calculate address of entry in string cache: each entry consists |
| 1363 // of two pointer sized fields. | 1346 // of two pointer sized fields. |
| 1364 __ sll(scratch, scratch, kPointerSizeLog2 + 1); | 1347 __ sll(scratch, scratch, kPointerSizeLog2 + 1); |
| 1365 __ Addu(scratch, number_string_cache, scratch); | 1348 __ Addu(scratch, number_string_cache, scratch); |
| 1366 | 1349 |
| 1367 // Check if the entry is the smi we are looking for. | 1350 // Check if the entry is the smi we are looking for. |
| 1368 Register probe = mask; | |
| 1369 __ lw(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize)); | 1351 __ lw(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize)); |
| 1370 __ Branch(not_found, ne, object, Operand(probe)); | 1352 __ Branch(not_found, ne, object, Operand(probe)); |
| 1371 | 1353 |
| 1372 // Get the result from the cache. | 1354 // Get the result from the cache. |
| 1373 __ bind(&load_result_from_cache); | 1355 __ bind(&load_result_from_cache); |
| 1374 __ lw(result, | 1356 __ lw(result, |
| 1375 FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize)); | 1357 FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize)); |
| 1376 | 1358 |
| 1377 __ IncrementCounter(isolate->counters()->number_to_string_native(), | 1359 __ IncrementCounter(isolate->counters()->number_to_string_native(), |
| 1378 1, | 1360 1, |
| 1379 scratch1, | 1361 scratch1, |
| 1380 scratch2); | 1362 scratch2); |
| 1381 } | 1363 } |
| 1382 | 1364 |
| 1383 | 1365 |
| 1384 void NumberToStringStub::Generate(MacroAssembler* masm) { | 1366 void NumberToStringStub::Generate(MacroAssembler* masm) { |
| 1385 Label runtime; | 1367 Label runtime; |
| 1386 | 1368 |
| 1387 __ lw(a1, MemOperand(sp, 0)); | 1369 __ lw(a1, MemOperand(sp, 0)); |
| 1388 | 1370 |
| 1389 // Generate code to lookup number in the number string cache. | 1371 // Generate code to lookup number in the number string cache. |
| 1390 GenerateLookupNumberStringCache(masm, a1, v0, a2, a3, t0, false, &runtime); | 1372 GenerateLookupNumberStringCache(masm, a1, v0, a2, a3, t0, &runtime); |
| 1391 __ DropAndRet(1); | 1373 __ DropAndRet(1); |
| 1392 | 1374 |
| 1393 __ bind(&runtime); | 1375 __ bind(&runtime); |
| 1394 // Handle number to string in the runtime system if not found in the cache. | 1376 // Handle number to string in the runtime system if not found in the cache. |
| 1395 __ TailCallRuntime(Runtime::kNumberToString, 1, 1); | 1377 __ TailCallRuntime(Runtime::kNumberToString, 1, 1); |
| 1396 } | 1378 } |
| 1397 | 1379 |
| 1398 | 1380 |
| 1399 static void ICCompareStub_CheckInputType(MacroAssembler* masm, | 1381 static void ICCompareStub_CheckInputType(MacroAssembler* masm, |
| 1400 Register input, | 1382 Register input, |
| (...skipping 725 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2126 // Test if left operand is a string. | 2108 // Test if left operand is a string. |
| 2127 __ JumpIfSmi(left, &call_runtime); | 2109 __ JumpIfSmi(left, &call_runtime); |
| 2128 __ GetObjectType(left, a2, a2); | 2110 __ GetObjectType(left, a2, a2); |
| 2129 __ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE)); | 2111 __ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE)); |
| 2130 | 2112 |
| 2131 // Test if right operand is a string. | 2113 // Test if right operand is a string. |
| 2132 __ JumpIfSmi(right, &call_runtime); | 2114 __ JumpIfSmi(right, &call_runtime); |
| 2133 __ GetObjectType(right, a2, a2); | 2115 __ GetObjectType(right, a2, a2); |
| 2134 __ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE)); | 2116 __ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE)); |
| 2135 | 2117 |
| 2136 StringAddStub string_add_stub((StringAddFlags) | 2118 StringAddStub string_add_stub( |
| 2137 (ERECT_FRAME | NO_STRING_CHECK_IN_STUB)); | 2119 (StringAddFlags)(STRING_ADD_CHECK_NONE | STRING_ADD_ERECT_FRAME)); |
| 2138 GenerateRegisterArgsPush(masm); | 2120 GenerateRegisterArgsPush(masm); |
| 2139 __ TailCallStub(&string_add_stub); | 2121 __ TailCallStub(&string_add_stub); |
| 2140 | 2122 |
| 2141 __ bind(&call_runtime); | 2123 __ bind(&call_runtime); |
| 2142 GenerateTypeTransition(masm); | 2124 GenerateTypeTransition(masm); |
| 2143 } | 2125 } |
| 2144 | 2126 |
| 2145 | 2127 |
| 2146 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { | 2128 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { |
| 2147 ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32); | 2129 ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32); |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2544 Label left_not_string, call_runtime; | 2526 Label left_not_string, call_runtime; |
| 2545 | 2527 |
| 2546 Register left = a1; | 2528 Register left = a1; |
| 2547 Register right = a0; | 2529 Register right = a0; |
| 2548 | 2530 |
| 2549 // Check if left argument is a string. | 2531 // Check if left argument is a string. |
| 2550 __ JumpIfSmi(left, &left_not_string); | 2532 __ JumpIfSmi(left, &left_not_string); |
| 2551 __ GetObjectType(left, a2, a2); | 2533 __ GetObjectType(left, a2, a2); |
| 2552 __ Branch(&left_not_string, ge, a2, Operand(FIRST_NONSTRING_TYPE)); | 2534 __ Branch(&left_not_string, ge, a2, Operand(FIRST_NONSTRING_TYPE)); |
| 2553 | 2535 |
| 2554 StringAddStub string_add_left_stub((StringAddFlags) | 2536 StringAddStub string_add_left_stub( |
| 2555 (ERECT_FRAME | NO_STRING_CHECK_LEFT_IN_STUB)); | 2537 (StringAddFlags)(STRING_ADD_CHECK_RIGHT | STRING_ADD_ERECT_FRAME)); |
| 2556 GenerateRegisterArgsPush(masm); | 2538 GenerateRegisterArgsPush(masm); |
| 2557 __ TailCallStub(&string_add_left_stub); | 2539 __ TailCallStub(&string_add_left_stub); |
| 2558 | 2540 |
| 2559 // Left operand is not a string, test right. | 2541 // Left operand is not a string, test right. |
| 2560 __ bind(&left_not_string); | 2542 __ bind(&left_not_string); |
| 2561 __ JumpIfSmi(right, &call_runtime); | 2543 __ JumpIfSmi(right, &call_runtime); |
| 2562 __ GetObjectType(right, a2, a2); | 2544 __ GetObjectType(right, a2, a2); |
| 2563 __ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE)); | 2545 __ Branch(&call_runtime, ge, a2, Operand(FIRST_NONSTRING_TYPE)); |
| 2564 | 2546 |
| 2565 StringAddStub string_add_right_stub((StringAddFlags) | 2547 StringAddStub string_add_right_stub( |
| 2566 (ERECT_FRAME | NO_STRING_CHECK_RIGHT_IN_STUB)); | 2548 (StringAddFlags)(STRING_ADD_CHECK_LEFT | STRING_ADD_ERECT_FRAME)); |
| 2567 GenerateRegisterArgsPush(masm); | 2549 GenerateRegisterArgsPush(masm); |
| 2568 __ TailCallStub(&string_add_right_stub); | 2550 __ TailCallStub(&string_add_right_stub); |
| 2569 | 2551 |
| 2570 // At least one argument is not a string. | 2552 // At least one argument is not a string. |
| 2571 __ bind(&call_runtime); | 2553 __ bind(&call_runtime); |
| 2572 } | 2554 } |
| 2573 | 2555 |
| 2574 | 2556 |
| 2575 void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, | 2557 void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, |
| 2576 Register result, | 2558 Register result, |
| (...skipping 3281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5858 | 5840 |
| 5859 // Stack on entry: | 5841 // Stack on entry: |
| 5860 // sp[0]: second argument (right). | 5842 // sp[0]: second argument (right). |
| 5861 // sp[4]: first argument (left). | 5843 // sp[4]: first argument (left). |
| 5862 | 5844 |
| 5863 // Load the two arguments. | 5845 // Load the two arguments. |
| 5864 __ lw(a0, MemOperand(sp, 1 * kPointerSize)); // First argument. | 5846 __ lw(a0, MemOperand(sp, 1 * kPointerSize)); // First argument. |
| 5865 __ lw(a1, MemOperand(sp, 0 * kPointerSize)); // Second argument. | 5847 __ lw(a1, MemOperand(sp, 0 * kPointerSize)); // Second argument. |
| 5866 | 5848 |
| 5867 // Make sure that both arguments are strings if not known in advance. | 5849 // Make sure that both arguments are strings if not known in advance. |
| 5868 if ((flags_ & NO_STRING_ADD_FLAGS) != 0) { | 5850 // Otherwise, at least one of the arguments is definitely a string, |
| 5851 // and we convert the one that is not known to be a string. |
| 5852 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { |
| 5853 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT); |
| 5854 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT); |
| 5869 __ JumpIfEitherSmi(a0, a1, &call_runtime); | 5855 __ JumpIfEitherSmi(a0, a1, &call_runtime); |
| 5870 // Load instance types. | 5856 // Load instance types. |
| 5871 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); | 5857 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); |
| 5872 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); | 5858 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); |
| 5873 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | 5859 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); |
| 5874 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); | 5860 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); |
| 5875 STATIC_ASSERT(kStringTag == 0); | 5861 STATIC_ASSERT(kStringTag == 0); |
| 5876 // If either is not a string, go to runtime. | 5862 // If either is not a string, go to runtime. |
| 5877 __ Or(t4, t0, Operand(t1)); | 5863 __ Or(t4, t0, Operand(t1)); |
| 5878 __ And(t4, t4, Operand(kIsNotStringMask)); | 5864 __ And(t4, t4, Operand(kIsNotStringMask)); |
| 5879 __ Branch(&call_runtime, ne, t4, Operand(zero_reg)); | 5865 __ Branch(&call_runtime, ne, t4, Operand(zero_reg)); |
| 5880 } else { | 5866 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { |
| 5881 // Here at least one of the arguments is definitely a string. | 5867 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); |
| 5882 // We convert the one that is not known to be a string. | 5868 GenerateConvertArgument( |
| 5883 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { | 5869 masm, 1 * kPointerSize, a0, a2, a3, t0, t1, &call_builtin); |
| 5884 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); | 5870 builtin_id = Builtins::STRING_ADD_RIGHT; |
| 5885 GenerateConvertArgument( | 5871 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { |
| 5886 masm, 1 * kPointerSize, a0, a2, a3, t0, t1, &call_builtin); | 5872 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0); |
| 5887 builtin_id = Builtins::STRING_ADD_RIGHT; | 5873 GenerateConvertArgument( |
| 5888 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { | 5874 masm, 0 * kPointerSize, a1, a2, a3, t0, t1, &call_builtin); |
| 5889 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); | 5875 builtin_id = Builtins::STRING_ADD_LEFT; |
| 5890 GenerateConvertArgument( | |
| 5891 masm, 0 * kPointerSize, a1, a2, a3, t0, t1, &call_builtin); | |
| 5892 builtin_id = Builtins::STRING_ADD_LEFT; | |
| 5893 } | |
| 5894 } | 5876 } |
| 5895 | 5877 |
| 5896 // Both arguments are strings. | 5878 // Both arguments are strings. |
| 5897 // a0: first string | 5879 // a0: first string |
| 5898 // a1: second string | 5880 // a1: second string |
| 5899 // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) | 5881 // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
| 5900 // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) | 5882 // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
| 5901 { | 5883 { |
| 5902 Label strings_not_empty; | 5884 Label strings_not_empty; |
| 5903 // Check if either of the strings are empty. In that case return the other. | 5885 // Check if either of the strings are empty. In that case return the other. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 5934 // Look at the length of the result of adding the two strings. | 5916 // Look at the length of the result of adding the two strings. |
| 5935 Label string_add_flat_result, longer_than_two; | 5917 Label string_add_flat_result, longer_than_two; |
| 5936 // Adding two lengths can't overflow. | 5918 // Adding two lengths can't overflow. |
| 5937 STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2); | 5919 STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2); |
| 5938 __ Addu(t2, a2, Operand(a3)); | 5920 __ Addu(t2, a2, Operand(a3)); |
| 5939 // Use the string table when adding two one character strings, as it | 5921 // Use the string table when adding two one character strings, as it |
| 5940 // helps later optimizations to return a string here. | 5922 // helps later optimizations to return a string here. |
| 5941 __ Branch(&longer_than_two, ne, t2, Operand(2)); | 5923 __ Branch(&longer_than_two, ne, t2, Operand(2)); |
| 5942 | 5924 |
| 5943 // Check that both strings are non-external ASCII strings. | 5925 // Check that both strings are non-external ASCII strings. |
| 5944 if (flags_ != NO_STRING_ADD_FLAGS) { | 5926 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { |
| 5945 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); | 5927 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); |
| 5946 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); | 5928 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); |
| 5947 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | 5929 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); |
| 5948 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); | 5930 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); |
| 5949 } | 5931 } |
| 5950 __ JumpIfBothInstanceTypesAreNotSequentialAscii(t0, t1, t2, t3, | 5932 __ JumpIfBothInstanceTypesAreNotSequentialAscii(t0, t1, t2, t3, |
| 5951 &call_runtime); | 5933 &call_runtime); |
| 5952 | 5934 |
| 5953 // Get the two characters forming the sub string. | 5935 // Get the two characters forming the sub string. |
| 5954 __ lbu(a2, FieldMemOperand(a0, SeqOneByteString::kHeaderSize)); | 5936 __ lbu(a2, FieldMemOperand(a0, SeqOneByteString::kHeaderSize)); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 5978 // Check if resulting string will be flat. | 5960 // Check if resulting string will be flat. |
| 5979 __ Branch(&string_add_flat_result, lt, t2, Operand(ConsString::kMinLength)); | 5961 __ Branch(&string_add_flat_result, lt, t2, Operand(ConsString::kMinLength)); |
| 5980 // Handle exceptionally long strings in the runtime system. | 5962 // Handle exceptionally long strings in the runtime system. |
| 5981 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); | 5963 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); |
| 5982 ASSERT(IsPowerOf2(String::kMaxLength + 1)); | 5964 ASSERT(IsPowerOf2(String::kMaxLength + 1)); |
| 5983 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. | 5965 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. |
| 5984 __ Branch(&call_runtime, hs, t2, Operand(String::kMaxLength + 1)); | 5966 __ Branch(&call_runtime, hs, t2, Operand(String::kMaxLength + 1)); |
| 5985 | 5967 |
| 5986 // If result is not supposed to be flat, allocate a cons string object. | 5968 // If result is not supposed to be flat, allocate a cons string object. |
| 5987 // If both strings are ASCII the result is an ASCII cons string. | 5969 // If both strings are ASCII the result is an ASCII cons string. |
| 5988 if (flags_ != NO_STRING_ADD_FLAGS) { | 5970 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { |
| 5989 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); | 5971 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); |
| 5990 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); | 5972 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); |
| 5991 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | 5973 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); |
| 5992 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); | 5974 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); |
| 5993 } | 5975 } |
| 5994 Label non_ascii, allocated, ascii_data; | 5976 Label non_ascii, allocated, ascii_data; |
| 5995 STATIC_ASSERT(kTwoByteStringTag == 0); | 5977 STATIC_ASSERT(kTwoByteStringTag == 0); |
| 5996 // Branch to non_ascii if either string-encoding field is zero (non-ASCII). | 5978 // Branch to non_ascii if either string-encoding field is zero (non-ASCII). |
| 5997 __ And(t4, t0, Operand(t1)); | 5979 __ And(t4, t0, Operand(t1)); |
| 5998 __ And(t4, t4, Operand(kStringEncodingMask)); | 5980 __ And(t4, t4, Operand(kStringEncodingMask)); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6061 // Locate the first characters' locations. | 6043 // Locate the first characters' locations. |
| 6062 // a0: first string | 6044 // a0: first string |
| 6063 // a1: second string | 6045 // a1: second string |
| 6064 // a2: length of first string | 6046 // a2: length of first string |
| 6065 // a3: length of second string | 6047 // a3: length of second string |
| 6066 // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) | 6048 // t0: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
| 6067 // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) | 6049 // t1: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
| 6068 // t2: sum of lengths. | 6050 // t2: sum of lengths. |
| 6069 Label first_prepared, second_prepared; | 6051 Label first_prepared, second_prepared; |
| 6070 __ bind(&string_add_flat_result); | 6052 __ bind(&string_add_flat_result); |
| 6071 if (flags_ != NO_STRING_ADD_FLAGS) { | 6053 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { |
| 6072 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); | 6054 __ lw(t0, FieldMemOperand(a0, HeapObject::kMapOffset)); |
| 6073 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); | 6055 __ lw(t1, FieldMemOperand(a1, HeapObject::kMapOffset)); |
| 6074 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); | 6056 __ lbu(t0, FieldMemOperand(t0, Map::kInstanceTypeOffset)); |
| 6075 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); | 6057 __ lbu(t1, FieldMemOperand(t1, Map::kInstanceTypeOffset)); |
| 6076 } | 6058 } |
| 6077 // Check whether both strings have same encoding | 6059 // Check whether both strings have same encoding |
| 6078 __ Xor(t3, t0, Operand(t1)); | 6060 __ Xor(t3, t0, Operand(t1)); |
| 6079 __ And(t3, t3, Operand(kStringEncodingMask)); | 6061 __ And(t3, t3, Operand(kStringEncodingMask)); |
| 6080 __ Branch(&call_runtime, ne, t3, Operand(zero_reg)); | 6062 __ Branch(&call_runtime, ne, t3, Operand(zero_reg)); |
| 6081 | 6063 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6147 // t2: first character of result. | 6129 // t2: first character of result. |
| 6148 StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, false); | 6130 StringHelper::GenerateCopyCharacters(masm, t2, t3, a2, t0, false); |
| 6149 // t2: next character of result. | 6131 // t2: next character of result. |
| 6150 StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, false); | 6132 StringHelper::GenerateCopyCharacters(masm, t2, a1, a3, t0, false); |
| 6151 | 6133 |
| 6152 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); | 6134 __ IncrementCounter(counters->string_add_native(), 1, a2, a3); |
| 6153 __ DropAndRet(2); | 6135 __ DropAndRet(2); |
| 6154 | 6136 |
| 6155 // Just jump to runtime to add the two strings. | 6137 // Just jump to runtime to add the two strings. |
| 6156 __ bind(&call_runtime); | 6138 __ bind(&call_runtime); |
| 6157 if ((flags_ & ERECT_FRAME) != 0) { | 6139 if ((flags_ & STRING_ADD_ERECT_FRAME) != 0) { |
| 6158 GenerateRegisterArgsPop(masm); | 6140 GenerateRegisterArgsPop(masm); |
| 6159 // Build a frame. | 6141 // Build a frame. |
| 6160 { | 6142 { |
| 6161 FrameScope scope(masm, StackFrame::INTERNAL); | 6143 FrameScope scope(masm, StackFrame::INTERNAL); |
| 6162 GenerateRegisterArgsPush(masm); | 6144 GenerateRegisterArgsPush(masm); |
| 6163 __ CallRuntime(Runtime::kStringAdd, 2); | 6145 __ CallRuntime(Runtime::kStringAdd, 2); |
| 6164 } | 6146 } |
| 6165 __ Ret(); | 6147 __ Ret(); |
| 6166 } else { | 6148 } else { |
| 6167 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 6149 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 6168 } | 6150 } |
| 6169 | 6151 |
| 6170 if (call_builtin.is_linked()) { | 6152 if (call_builtin.is_linked()) { |
| 6171 __ bind(&call_builtin); | 6153 __ bind(&call_builtin); |
| 6172 if ((flags_ & ERECT_FRAME) != 0) { | 6154 if ((flags_ & STRING_ADD_ERECT_FRAME) != 0) { |
| 6173 GenerateRegisterArgsPop(masm); | 6155 GenerateRegisterArgsPop(masm); |
| 6174 // Build a frame. | 6156 // Build a frame. |
| 6175 { | 6157 { |
| 6176 FrameScope scope(masm, StackFrame::INTERNAL); | 6158 FrameScope scope(masm, StackFrame::INTERNAL); |
| 6177 GenerateRegisterArgsPush(masm); | 6159 GenerateRegisterArgsPush(masm); |
| 6178 __ InvokeBuiltin(builtin_id, CALL_FUNCTION); | 6160 __ InvokeBuiltin(builtin_id, CALL_FUNCTION); |
| 6179 } | 6161 } |
| 6180 __ Ret(); | 6162 __ Ret(); |
| 6181 } else { | 6163 } else { |
| 6182 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | 6164 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6214 // Check the number to string cache. | 6196 // Check the number to string cache. |
| 6215 Label not_cached; | 6197 Label not_cached; |
| 6216 __ bind(¬_string); | 6198 __ bind(¬_string); |
| 6217 // Puts the cached result into scratch1. | 6199 // Puts the cached result into scratch1. |
| 6218 NumberToStringStub::GenerateLookupNumberStringCache(masm, | 6200 NumberToStringStub::GenerateLookupNumberStringCache(masm, |
| 6219 arg, | 6201 arg, |
| 6220 scratch1, | 6202 scratch1, |
| 6221 scratch2, | 6203 scratch2, |
| 6222 scratch3, | 6204 scratch3, |
| 6223 scratch4, | 6205 scratch4, |
| 6224 false, | |
| 6225 ¬_cached); | 6206 ¬_cached); |
| 6226 __ mov(arg, scratch1); | 6207 __ mov(arg, scratch1); |
| 6227 __ sw(arg, MemOperand(sp, stack_offset)); | 6208 __ sw(arg, MemOperand(sp, stack_offset)); |
| 6228 __ jmp(&done); | 6209 __ jmp(&done); |
| 6229 | 6210 |
| 6230 // Check if the argument is a safe string wrapper. | 6211 // Check if the argument is a safe string wrapper. |
| 6231 __ bind(¬_cached); | 6212 __ bind(¬_cached); |
| 6232 __ JumpIfSmi(arg, slow); | 6213 __ JumpIfSmi(arg, slow); |
| 6233 __ GetObjectType(arg, scratch1, scratch2); // map -> scratch1. | 6214 __ GetObjectType(arg, scratch1, scratch2); // map -> scratch1. |
| 6234 __ Branch(slow, ne, scratch2, Operand(JS_VALUE_TYPE)); | 6215 __ Branch(slow, ne, scratch2, Operand(JS_VALUE_TYPE)); |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6370 Register tmp2 = a3; | 6351 Register tmp2 = a3; |
| 6371 | 6352 |
| 6372 // Check that both operands are heap objects. | 6353 // Check that both operands are heap objects. |
| 6373 __ JumpIfEitherSmi(left, right, &miss); | 6354 __ JumpIfEitherSmi(left, right, &miss); |
| 6374 | 6355 |
| 6375 // Check that both operands are internalized strings. | 6356 // Check that both operands are internalized strings. |
| 6376 __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); | 6357 __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); |
| 6377 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | 6358 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); |
| 6378 __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); | 6359 __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); |
| 6379 __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); | 6360 __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); |
| 6380 STATIC_ASSERT(kInternalizedTag != 0); | 6361 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
| 6381 | 6362 __ Or(tmp1, tmp1, Operand(tmp2)); |
| 6382 __ And(tmp1, tmp1, Operand(kIsNotStringMask | kIsInternalizedMask)); | 6363 __ And(at, tmp1, Operand(kIsNotStringMask | kIsNotInternalizedMask)); |
| 6383 __ Branch(&miss, ne, tmp1, Operand(kInternalizedTag | kStringTag)); | 6364 __ Branch(&miss, ne, at, Operand(zero_reg)); |
| 6384 | |
| 6385 __ And(tmp2, tmp2, Operand(kIsNotStringMask | kIsInternalizedMask)); | |
| 6386 __ Branch(&miss, ne, tmp2, Operand(kInternalizedTag | kStringTag)); | |
| 6387 | 6365 |
| 6388 // Make sure a0 is non-zero. At this point input operands are | 6366 // Make sure a0 is non-zero. At this point input operands are |
| 6389 // guaranteed to be non-zero. | 6367 // guaranteed to be non-zero. |
| 6390 ASSERT(right.is(a0)); | 6368 ASSERT(right.is(a0)); |
| 6391 STATIC_ASSERT(EQUAL == 0); | 6369 STATIC_ASSERT(EQUAL == 0); |
| 6392 STATIC_ASSERT(kSmiTag == 0); | 6370 STATIC_ASSERT(kSmiTag == 0); |
| 6393 __ mov(v0, right); | 6371 __ mov(v0, right); |
| 6394 // Internalized strings are compared by identity. | 6372 // Internalized strings are compared by identity. |
| 6395 __ Ret(ne, left, Operand(right)); | 6373 __ Ret(ne, left, Operand(right)); |
| 6396 ASSERT(is_int16(EQUAL)); | 6374 ASSERT(is_int16(EQUAL)); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 6411 Register left = a1; | 6389 Register left = a1; |
| 6412 Register right = a0; | 6390 Register right = a0; |
| 6413 Register tmp1 = a2; | 6391 Register tmp1 = a2; |
| 6414 Register tmp2 = a3; | 6392 Register tmp2 = a3; |
| 6415 | 6393 |
| 6416 // Check that both operands are heap objects. | 6394 // Check that both operands are heap objects. |
| 6417 __ JumpIfEitherSmi(left, right, &miss); | 6395 __ JumpIfEitherSmi(left, right, &miss); |
| 6418 | 6396 |
| 6419 // Check that both operands are unique names. This leaves the instance | 6397 // Check that both operands are unique names. This leaves the instance |
| 6420 // types loaded in tmp1 and tmp2. | 6398 // types loaded in tmp1 and tmp2. |
| 6421 STATIC_ASSERT(kInternalizedTag != 0); | |
| 6422 __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); | 6399 __ lw(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); |
| 6423 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | 6400 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); |
| 6424 __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); | 6401 __ lbu(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); |
| 6425 __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); | 6402 __ lbu(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); |
| 6426 | 6403 |
| 6427 __ JumpIfNotUniqueName(tmp1, &miss); | 6404 __ JumpIfNotUniqueName(tmp1, &miss); |
| 6428 __ JumpIfNotUniqueName(tmp2, &miss); | 6405 __ JumpIfNotUniqueName(tmp2, &miss); |
| 6429 | 6406 |
| 6430 // Use a0 as result | 6407 // Use a0 as result |
| 6431 __ mov(v0, a0); | 6408 __ mov(v0, a0); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6485 __ mov(v0, zero_reg); // In the delay slot. | 6462 __ mov(v0, zero_reg); // In the delay slot. |
| 6486 __ bind(&left_ne_right); | 6463 __ bind(&left_ne_right); |
| 6487 | 6464 |
| 6488 // Handle not identical strings. | 6465 // Handle not identical strings. |
| 6489 | 6466 |
| 6490 // Check that both strings are internalized strings. If they are, we're done | 6467 // Check that both strings are internalized strings. If they are, we're done |
| 6491 // because we already know they are not identical. We know they are both | 6468 // because we already know they are not identical. We know they are both |
| 6492 // strings. | 6469 // strings. |
| 6493 if (equality) { | 6470 if (equality) { |
| 6494 ASSERT(GetCondition() == eq); | 6471 ASSERT(GetCondition() == eq); |
| 6495 STATIC_ASSERT(kInternalizedTag != 0); | 6472 STATIC_ASSERT(kInternalizedTag == 0); |
| 6496 __ And(tmp3, tmp1, Operand(tmp2)); | 6473 __ Or(tmp3, tmp1, Operand(tmp2)); |
| 6497 __ And(tmp5, tmp3, Operand(kIsInternalizedMask)); | 6474 __ And(tmp5, tmp3, Operand(kIsNotInternalizedMask)); |
| 6498 Label is_symbol; | 6475 Label is_symbol; |
| 6499 __ Branch(&is_symbol, eq, tmp5, Operand(zero_reg)); | 6476 __ Branch(&is_symbol, ne, tmp5, Operand(zero_reg)); |
| 6500 // Make sure a0 is non-zero. At this point input operands are | 6477 // Make sure a0 is non-zero. At this point input operands are |
| 6501 // guaranteed to be non-zero. | 6478 // guaranteed to be non-zero. |
| 6502 ASSERT(right.is(a0)); | 6479 ASSERT(right.is(a0)); |
| 6503 __ Ret(USE_DELAY_SLOT); | 6480 __ Ret(USE_DELAY_SLOT); |
| 6504 __ mov(v0, a0); // In the delay slot. | 6481 __ mov(v0, a0); // In the delay slot. |
| 6505 __ bind(&is_symbol); | 6482 __ bind(&is_symbol); |
| 6506 } | 6483 } |
| 6507 | 6484 |
| 6508 // Check that both strings are sequential ASCII. | 6485 // Check that both strings are sequential ASCII. |
| 6509 Label runtime; | 6486 Label runtime; |
| (...skipping 1104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7614 __ bind(&fast_elements_case); | 7591 __ bind(&fast_elements_case); |
| 7615 GenerateCase(masm, FAST_ELEMENTS); | 7592 GenerateCase(masm, FAST_ELEMENTS); |
| 7616 } | 7593 } |
| 7617 | 7594 |
| 7618 | 7595 |
| 7619 #undef __ | 7596 #undef __ |
| 7620 | 7597 |
| 7621 } } // namespace v8::internal | 7598 } } // namespace v8::internal |
| 7622 | 7599 |
| 7623 #endif // V8_TARGET_ARCH_MIPS | 7600 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |