| 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 20 matching lines...) Expand all Loading... |
| 31 | 31 |
| 32 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
| 33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
| 34 #include "regexp-macro-assembler.h" | 34 #include "regexp-macro-assembler.h" |
| 35 #include "stub-cache.h" | 35 #include "stub-cache.h" |
| 36 | 36 |
| 37 namespace v8 { | 37 namespace v8 { |
| 38 namespace internal { | 38 namespace internal { |
| 39 | 39 |
| 40 | 40 |
| 41 void ToNumberStub::InitializeInterfaceDescriptor( |
| 42 Isolate* isolate, |
| 43 CodeStubInterfaceDescriptor* descriptor) { |
| 44 static Register registers[] = { r0 }; |
| 45 descriptor->register_param_count_ = 1; |
| 46 descriptor->register_params_ = registers; |
| 47 descriptor->deoptimization_handler_ = NULL; |
| 48 } |
| 49 |
| 50 |
| 41 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor( | 51 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor( |
| 42 Isolate* isolate, | 52 Isolate* isolate, |
| 43 CodeStubInterfaceDescriptor* descriptor) { | 53 CodeStubInterfaceDescriptor* descriptor) { |
| 44 static Register registers[] = { r3, r2, r1 }; | 54 static Register registers[] = { r3, r2, r1 }; |
| 45 descriptor->register_param_count_ = 3; | 55 descriptor->register_param_count_ = 3; |
| 46 descriptor->register_params_ = registers; | 56 descriptor->register_params_ = registers; |
| 47 descriptor->deoptimization_handler_ = | 57 descriptor->deoptimization_handler_ = |
| 48 Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry; | 58 Runtime::FunctionForId(Runtime::kCreateArrayLiteralShallow)->entry; |
| 49 } | 59 } |
| 50 | 60 |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 Isolate* isolate, | 261 Isolate* isolate, |
| 252 CodeStubInterfaceDescriptor* descriptor) { | 262 CodeStubInterfaceDescriptor* descriptor) { |
| 253 static Register registers[] = { r1, r2, r0 }; | 263 static Register registers[] = { r1, r2, r0 }; |
| 254 descriptor->register_param_count_ = 3; | 264 descriptor->register_param_count_ = 3; |
| 255 descriptor->register_params_ = registers; | 265 descriptor->register_params_ = registers; |
| 256 descriptor->deoptimization_handler_ = | 266 descriptor->deoptimization_handler_ = |
| 257 FUNCTION_ADDR(StoreIC_MissFromStubFailure); | 267 FUNCTION_ADDR(StoreIC_MissFromStubFailure); |
| 258 } | 268 } |
| 259 | 269 |
| 260 | 270 |
| 271 void ElementsTransitionAndStoreStub::InitializeInterfaceDescriptor( |
| 272 Isolate* isolate, |
| 273 CodeStubInterfaceDescriptor* descriptor) { |
| 274 static Register registers[] = { r0, r3, r1, r2 }; |
| 275 descriptor->register_param_count_ = 4; |
| 276 descriptor->register_params_ = registers; |
| 277 descriptor->deoptimization_handler_ = |
| 278 FUNCTION_ADDR(ElementsTransitionAndStoreIC_Miss); |
| 279 } |
| 280 |
| 281 |
| 261 #define __ ACCESS_MASM(masm) | 282 #define __ ACCESS_MASM(masm) |
| 262 | 283 |
| 263 | 284 |
| 264 static void EmitIdenticalObjectComparison(MacroAssembler* masm, | 285 static void EmitIdenticalObjectComparison(MacroAssembler* masm, |
| 265 Label* slow, | 286 Label* slow, |
| 266 Condition cond); | 287 Condition cond); |
| 267 static void EmitSmiNonsmiComparison(MacroAssembler* masm, | 288 static void EmitSmiNonsmiComparison(MacroAssembler* masm, |
| 268 Register lhs, | 289 Register lhs, |
| 269 Register rhs, | 290 Register rhs, |
| 270 Label* lhs_not_nan, | 291 Label* lhs_not_nan, |
| 271 Label* slow, | 292 Label* slow, |
| 272 bool strict); | 293 bool strict); |
| 273 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, | 294 static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm, |
| 274 Register lhs, | 295 Register lhs, |
| 275 Register rhs); | 296 Register rhs); |
| 276 | 297 |
| 277 | 298 |
| 278 // Check if the operand is a heap number. | |
| 279 static void EmitCheckForHeapNumber(MacroAssembler* masm, Register operand, | |
| 280 Register scratch1, Register scratch2, | |
| 281 Label* not_a_heap_number) { | |
| 282 __ ldr(scratch1, FieldMemOperand(operand, HeapObject::kMapOffset)); | |
| 283 __ LoadRoot(scratch2, Heap::kHeapNumberMapRootIndex); | |
| 284 __ cmp(scratch1, scratch2); | |
| 285 __ b(ne, not_a_heap_number); | |
| 286 } | |
| 287 | |
| 288 | |
| 289 void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { | 299 void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm) { |
| 290 // Update the static counter each time a new code stub is generated. | 300 // Update the static counter each time a new code stub is generated. |
| 291 Isolate* isolate = masm->isolate(); | 301 Isolate* isolate = masm->isolate(); |
| 292 isolate->counters()->code_stubs()->Increment(); | 302 isolate->counters()->code_stubs()->Increment(); |
| 293 | 303 |
| 294 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate); | 304 CodeStubInterfaceDescriptor* descriptor = GetInterfaceDescriptor(isolate); |
| 295 int param_count = descriptor->register_param_count_; | 305 int param_count = descriptor->register_param_count_; |
| 296 { | 306 { |
| 297 // Call the runtime system in a fresh internal frame. | 307 // Call the runtime system in a fresh internal frame. |
| 298 FrameScope scope(masm, StackFrame::INTERNAL); | 308 FrameScope scope(masm, StackFrame::INTERNAL); |
| 299 ASSERT(descriptor->register_param_count_ == 0 || | 309 ASSERT(descriptor->register_param_count_ == 0 || |
| 300 r0.is(descriptor->register_params_[param_count - 1])); | 310 r0.is(descriptor->register_params_[param_count - 1])); |
| 301 // Push arguments | 311 // Push arguments |
| 302 for (int i = 0; i < param_count; ++i) { | 312 for (int i = 0; i < param_count; ++i) { |
| 303 __ push(descriptor->register_params_[i]); | 313 __ push(descriptor->register_params_[i]); |
| 304 } | 314 } |
| 305 ExternalReference miss = descriptor->miss_handler(); | 315 ExternalReference miss = descriptor->miss_handler(); |
| 306 __ CallExternalReference(miss, descriptor->register_param_count_); | 316 __ CallExternalReference(miss, descriptor->register_param_count_); |
| 307 } | 317 } |
| 308 | 318 |
| 309 __ Ret(); | 319 __ Ret(); |
| 310 } | 320 } |
| 311 | 321 |
| 312 | 322 |
| 313 void ToNumberStub::Generate(MacroAssembler* masm) { | |
| 314 // The ToNumber stub takes one argument in eax. | |
| 315 Label check_heap_number, call_builtin; | |
| 316 __ JumpIfNotSmi(r0, &check_heap_number); | |
| 317 __ Ret(); | |
| 318 | |
| 319 __ bind(&check_heap_number); | |
| 320 EmitCheckForHeapNumber(masm, r0, r1, ip, &call_builtin); | |
| 321 __ Ret(); | |
| 322 | |
| 323 __ bind(&call_builtin); | |
| 324 __ push(r0); | |
| 325 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); | |
| 326 } | |
| 327 | |
| 328 | |
| 329 void FastNewClosureStub::Generate(MacroAssembler* masm) { | 323 void FastNewClosureStub::Generate(MacroAssembler* masm) { |
| 330 // Create a new closure from the given function info in new | 324 // Create a new closure from the given function info in new |
| 331 // space. Set the context to the current context in cp. | 325 // space. Set the context to the current context in cp. |
| 332 Counters* counters = masm->isolate()->counters(); | 326 Counters* counters = masm->isolate()->counters(); |
| 333 | 327 |
| 334 Label gc; | 328 Label gc; |
| 335 | 329 |
| 336 // Pop the function info from the stack. | 330 // Pop the function info from the stack. |
| 337 __ pop(r3); | 331 __ pop(r3); |
| 338 | 332 |
| (...skipping 579 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 918 | 912 |
| 919 __ CompareObjectType(lhs, r3, r3, FIRST_SPEC_OBJECT_TYPE); | 913 __ CompareObjectType(lhs, r3, r3, FIRST_SPEC_OBJECT_TYPE); |
| 920 __ b(ge, &return_not_equal); | 914 __ b(ge, &return_not_equal); |
| 921 | 915 |
| 922 // Check for oddballs: true, false, null, undefined. | 916 // Check for oddballs: true, false, null, undefined. |
| 923 __ cmp(r3, Operand(ODDBALL_TYPE)); | 917 __ cmp(r3, Operand(ODDBALL_TYPE)); |
| 924 __ b(eq, &return_not_equal); | 918 __ b(eq, &return_not_equal); |
| 925 | 919 |
| 926 // Now that we have the types we might as well check for | 920 // Now that we have the types we might as well check for |
| 927 // internalized-internalized. | 921 // internalized-internalized. |
| 928 Label not_internalized; | 922 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
| 929 STATIC_ASSERT(kInternalizedTag != 0); | 923 __ orr(r2, r2, Operand(r3)); |
| 930 __ and_(r2, r2, Operand(kIsNotStringMask | kIsInternalizedMask)); | 924 __ tst(r2, Operand(kIsNotStringMask | kIsNotInternalizedMask)); |
| 931 __ cmp(r2, Operand(kInternalizedTag | kStringTag)); | 925 __ b(eq, &return_not_equal); |
| 932 __ b(ne, ¬_internalized); // r2 (rhs) is not an internalized string | |
| 933 | |
| 934 __ and_(r3, r3, Operand(kIsNotStringMask | kIsInternalizedMask)); | |
| 935 __ cmp(r3, Operand(kInternalizedTag | kStringTag)); | |
| 936 __ b(eq, &return_not_equal); // both rhs and lhs are internalized strings | |
| 937 | |
| 938 __ bind(¬_internalized); | |
| 939 } | 926 } |
| 940 | 927 |
| 941 | 928 |
| 942 // See comment at call site. | 929 // See comment at call site. |
| 943 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, | 930 static void EmitCheckForTwoHeapNumbers(MacroAssembler* masm, |
| 944 Register lhs, | 931 Register lhs, |
| 945 Register rhs, | 932 Register rhs, |
| 946 Label* both_loaded_as_doubles, | 933 Label* both_loaded_as_doubles, |
| 947 Label* not_heap_numbers, | 934 Label* not_heap_numbers, |
| 948 Label* slow) { | 935 Label* slow) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 969 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm, | 956 static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm, |
| 970 Register lhs, | 957 Register lhs, |
| 971 Register rhs, | 958 Register rhs, |
| 972 Label* possible_strings, | 959 Label* possible_strings, |
| 973 Label* not_both_strings) { | 960 Label* not_both_strings) { |
| 974 ASSERT((lhs.is(r0) && rhs.is(r1)) || | 961 ASSERT((lhs.is(r0) && rhs.is(r1)) || |
| 975 (lhs.is(r1) && rhs.is(r0))); | 962 (lhs.is(r1) && rhs.is(r0))); |
| 976 | 963 |
| 977 // r2 is object type of rhs. | 964 // r2 is object type of rhs. |
| 978 Label object_test; | 965 Label object_test; |
| 979 STATIC_ASSERT(kInternalizedTag != 0); | 966 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
| 980 __ tst(r2, Operand(kIsNotStringMask)); | 967 __ tst(r2, Operand(kIsNotStringMask)); |
| 981 __ b(ne, &object_test); | 968 __ b(ne, &object_test); |
| 982 __ tst(r2, Operand(kIsInternalizedMask)); | 969 __ tst(r2, Operand(kIsNotInternalizedMask)); |
| 983 __ b(eq, possible_strings); | 970 __ b(ne, possible_strings); |
| 984 __ CompareObjectType(lhs, r3, r3, FIRST_NONSTRING_TYPE); | 971 __ CompareObjectType(lhs, r3, r3, FIRST_NONSTRING_TYPE); |
| 985 __ b(ge, not_both_strings); | 972 __ b(ge, not_both_strings); |
| 986 __ tst(r3, Operand(kIsInternalizedMask)); | 973 __ tst(r3, Operand(kIsNotInternalizedMask)); |
| 987 __ b(eq, possible_strings); | 974 __ b(ne, possible_strings); |
| 988 | 975 |
| 989 // Both are internalized. We already checked they weren't the same pointer | 976 // Both are internalized. We already checked they weren't the same pointer |
| 990 // so they are not equal. | 977 // so they are not equal. |
| 991 __ mov(r0, Operand(NOT_EQUAL)); | 978 __ mov(r0, Operand(NOT_EQUAL)); |
| 992 __ Ret(); | 979 __ Ret(); |
| 993 | 980 |
| 994 __ bind(&object_test); | 981 __ bind(&object_test); |
| 995 __ cmp(r2, Operand(FIRST_SPEC_OBJECT_TYPE)); | 982 __ cmp(r2, Operand(FIRST_SPEC_OBJECT_TYPE)); |
| 996 __ b(lt, not_both_strings); | 983 __ b(lt, not_both_strings); |
| 997 __ CompareObjectType(lhs, r2, r3, FIRST_SPEC_OBJECT_TYPE); | 984 __ CompareObjectType(lhs, r2, r3, FIRST_SPEC_OBJECT_TYPE); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1008 __ Ret(); | 995 __ Ret(); |
| 1009 } | 996 } |
| 1010 | 997 |
| 1011 | 998 |
| 1012 void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, | 999 void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, |
| 1013 Register object, | 1000 Register object, |
| 1014 Register result, | 1001 Register result, |
| 1015 Register scratch1, | 1002 Register scratch1, |
| 1016 Register scratch2, | 1003 Register scratch2, |
| 1017 Register scratch3, | 1004 Register scratch3, |
| 1018 bool object_is_smi, | |
| 1019 Label* not_found) { | 1005 Label* not_found) { |
| 1020 // Use of registers. Register result is used as a temporary. | 1006 // Use of registers. Register result is used as a temporary. |
| 1021 Register number_string_cache = result; | 1007 Register number_string_cache = result; |
| 1022 Register mask = scratch3; | 1008 Register mask = scratch3; |
| 1023 | 1009 |
| 1024 // Load the number string cache. | 1010 // Load the number string cache. |
| 1025 __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex); | 1011 __ LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex); |
| 1026 | 1012 |
| 1027 // Make the hash mask from the length of the number string cache. It | 1013 // Make the hash mask from the length of the number string cache. It |
| 1028 // contains two elements (number and string) for each cache entry. | 1014 // contains two elements (number and string) for each cache entry. |
| 1029 __ ldr(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset)); | 1015 __ ldr(mask, FieldMemOperand(number_string_cache, FixedArray::kLengthOffset)); |
| 1030 // Divide length by two (length is a smi). | 1016 // Divide length by two (length is a smi). |
| 1031 __ mov(mask, Operand(mask, ASR, kSmiTagSize + 1)); | 1017 __ mov(mask, Operand(mask, ASR, kSmiTagSize + 1)); |
| 1032 __ sub(mask, mask, Operand(1)); // Make mask. | 1018 __ sub(mask, mask, Operand(1)); // Make mask. |
| 1033 | 1019 |
| 1034 // Calculate the entry in the number string cache. The hash value in the | 1020 // Calculate the entry in the number string cache. The hash value in the |
| 1035 // number string cache for smis is just the smi value, and the hash for | 1021 // number string cache for smis is just the smi value, and the hash for |
| 1036 // doubles is the xor of the upper and lower words. See | 1022 // doubles is the xor of the upper and lower words. See |
| 1037 // Heap::GetNumberStringCache. | 1023 // Heap::GetNumberStringCache. |
| 1038 Isolate* isolate = masm->isolate(); | 1024 Isolate* isolate = masm->isolate(); |
| 1039 Label is_smi; | 1025 Label is_smi; |
| 1040 Label load_result_from_cache; | 1026 Label load_result_from_cache; |
| 1041 if (!object_is_smi) { | 1027 __ JumpIfSmi(object, &is_smi); |
| 1042 __ JumpIfSmi(object, &is_smi); | 1028 __ CheckMap(object, |
| 1043 __ CheckMap(object, | 1029 scratch1, |
| 1044 scratch1, | 1030 Heap::kHeapNumberMapRootIndex, |
| 1045 Heap::kHeapNumberMapRootIndex, | 1031 not_found, |
| 1046 not_found, | 1032 DONT_DO_SMI_CHECK); |
| 1047 DONT_DO_SMI_CHECK); | |
| 1048 | 1033 |
| 1049 STATIC_ASSERT(8 == kDoubleSize); | 1034 STATIC_ASSERT(8 == kDoubleSize); |
| 1050 __ add(scratch1, | 1035 __ add(scratch1, |
| 1051 object, | 1036 object, |
| 1052 Operand(HeapNumber::kValueOffset - kHeapObjectTag)); | 1037 Operand(HeapNumber::kValueOffset - kHeapObjectTag)); |
| 1053 __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit()); | 1038 __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit()); |
| 1054 __ eor(scratch1, scratch1, Operand(scratch2)); | 1039 __ eor(scratch1, scratch1, Operand(scratch2)); |
| 1055 __ and_(scratch1, scratch1, Operand(mask)); | 1040 __ and_(scratch1, scratch1, Operand(mask)); |
| 1056 | 1041 |
| 1057 // Calculate address of entry in string cache: each entry consists | 1042 // Calculate address of entry in string cache: each entry consists |
| 1058 // of two pointer sized fields. | 1043 // of two pointer sized fields. |
| 1059 __ add(scratch1, | 1044 __ add(scratch1, |
| 1060 number_string_cache, | 1045 number_string_cache, |
| 1061 Operand(scratch1, LSL, kPointerSizeLog2 + 1)); | 1046 Operand(scratch1, LSL, kPointerSizeLog2 + 1)); |
| 1062 | 1047 |
| 1063 Register probe = mask; | 1048 Register probe = mask; |
| 1064 __ ldr(probe, | 1049 __ ldr(probe, |
| 1065 FieldMemOperand(scratch1, FixedArray::kHeaderSize)); | 1050 FieldMemOperand(scratch1, FixedArray::kHeaderSize)); |
| 1066 __ JumpIfSmi(probe, not_found); | 1051 __ JumpIfSmi(probe, not_found); |
| 1067 __ sub(scratch2, object, Operand(kHeapObjectTag)); | 1052 __ sub(scratch2, object, Operand(kHeapObjectTag)); |
| 1068 __ vldr(d0, scratch2, HeapNumber::kValueOffset); | 1053 __ vldr(d0, scratch2, HeapNumber::kValueOffset); |
| 1069 __ sub(probe, probe, Operand(kHeapObjectTag)); | 1054 __ sub(probe, probe, Operand(kHeapObjectTag)); |
| 1070 __ vldr(d1, probe, HeapNumber::kValueOffset); | 1055 __ vldr(d1, probe, HeapNumber::kValueOffset); |
| 1071 __ VFPCompareAndSetFlags(d0, d1); | 1056 __ VFPCompareAndSetFlags(d0, d1); |
| 1072 __ b(ne, not_found); // The cache did not contain this value. | 1057 __ b(ne, not_found); // The cache did not contain this value. |
| 1073 __ b(&load_result_from_cache); | 1058 __ b(&load_result_from_cache); |
| 1074 } | |
| 1075 | 1059 |
| 1076 __ bind(&is_smi); | 1060 __ bind(&is_smi); |
| 1077 Register scratch = scratch1; | 1061 Register scratch = scratch1; |
| 1078 __ and_(scratch, mask, Operand(object, ASR, 1)); | 1062 __ and_(scratch, mask, Operand(object, ASR, 1)); |
| 1079 // Calculate address of entry in string cache: each entry consists | 1063 // Calculate address of entry in string cache: each entry consists |
| 1080 // of two pointer sized fields. | 1064 // of two pointer sized fields. |
| 1081 __ add(scratch, | 1065 __ add(scratch, |
| 1082 number_string_cache, | 1066 number_string_cache, |
| 1083 Operand(scratch, LSL, kPointerSizeLog2 + 1)); | 1067 Operand(scratch, LSL, kPointerSizeLog2 + 1)); |
| 1084 | 1068 |
| 1085 // Check if the entry is the smi we are looking for. | 1069 // Check if the entry is the smi we are looking for. |
| 1086 Register probe = mask; | |
| 1087 __ ldr(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize)); | 1070 __ ldr(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize)); |
| 1088 __ cmp(object, probe); | 1071 __ cmp(object, probe); |
| 1089 __ b(ne, not_found); | 1072 __ b(ne, not_found); |
| 1090 | 1073 |
| 1091 // Get the result from the cache. | 1074 // Get the result from the cache. |
| 1092 __ bind(&load_result_from_cache); | 1075 __ bind(&load_result_from_cache); |
| 1093 __ ldr(result, | 1076 __ ldr(result, |
| 1094 FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize)); | 1077 FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize)); |
| 1095 __ IncrementCounter(isolate->counters()->number_to_string_native(), | 1078 __ IncrementCounter(isolate->counters()->number_to_string_native(), |
| 1096 1, | 1079 1, |
| 1097 scratch1, | 1080 scratch1, |
| 1098 scratch2); | 1081 scratch2); |
| 1099 } | 1082 } |
| 1100 | 1083 |
| 1101 | 1084 |
| 1102 void NumberToStringStub::Generate(MacroAssembler* masm) { | 1085 void NumberToStringStub::Generate(MacroAssembler* masm) { |
| 1103 Label runtime; | 1086 Label runtime; |
| 1104 | 1087 |
| 1105 __ ldr(r1, MemOperand(sp, 0)); | 1088 __ ldr(r1, MemOperand(sp, 0)); |
| 1106 | 1089 |
| 1107 // Generate code to lookup number in the number string cache. | 1090 // Generate code to lookup number in the number string cache. |
| 1108 GenerateLookupNumberStringCache(masm, r1, r0, r2, r3, r4, false, &runtime); | 1091 GenerateLookupNumberStringCache(masm, r1, r0, r2, r3, r4, &runtime); |
| 1109 __ add(sp, sp, Operand(1 * kPointerSize)); | 1092 __ add(sp, sp, Operand(1 * kPointerSize)); |
| 1110 __ Ret(); | 1093 __ Ret(); |
| 1111 | 1094 |
| 1112 __ bind(&runtime); | 1095 __ bind(&runtime); |
| 1113 // Handle number to string in the runtime system if not found in the cache. | 1096 // Handle number to string in the runtime system if not found in the cache. |
| 1114 __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1); | 1097 __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1); |
| 1115 } | 1098 } |
| 1116 | 1099 |
| 1117 | 1100 |
| 1118 static void ICCompareStub_CheckInputType(MacroAssembler* masm, | 1101 static void ICCompareStub_CheckInputType(MacroAssembler* masm, |
| (...skipping 771 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1890 // Test if left operand is a string. | 1873 // Test if left operand is a string. |
| 1891 __ JumpIfSmi(left, &call_runtime); | 1874 __ JumpIfSmi(left, &call_runtime); |
| 1892 __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE); | 1875 __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE); |
| 1893 __ b(ge, &call_runtime); | 1876 __ b(ge, &call_runtime); |
| 1894 | 1877 |
| 1895 // Test if right operand is a string. | 1878 // Test if right operand is a string. |
| 1896 __ JumpIfSmi(right, &call_runtime); | 1879 __ JumpIfSmi(right, &call_runtime); |
| 1897 __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE); | 1880 __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE); |
| 1898 __ b(ge, &call_runtime); | 1881 __ b(ge, &call_runtime); |
| 1899 | 1882 |
| 1900 StringAddStub string_add_stub((StringAddFlags) | 1883 StringAddStub string_add_stub( |
| 1901 (ERECT_FRAME | NO_STRING_CHECK_IN_STUB)); | 1884 (StringAddFlags)(STRING_ADD_CHECK_NONE | STRING_ADD_ERECT_FRAME)); |
| 1902 GenerateRegisterArgsPush(masm); | 1885 GenerateRegisterArgsPush(masm); |
| 1903 __ TailCallStub(&string_add_stub); | 1886 __ TailCallStub(&string_add_stub); |
| 1904 | 1887 |
| 1905 __ bind(&call_runtime); | 1888 __ bind(&call_runtime); |
| 1906 GenerateTypeTransition(masm); | 1889 GenerateTypeTransition(masm); |
| 1907 } | 1890 } |
| 1908 | 1891 |
| 1909 | 1892 |
| 1910 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { | 1893 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { |
| 1911 ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32); | 1894 ASSERT(Max(left_type_, right_type_) == BinaryOpIC::INT32); |
| (...skipping 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2249 Label left_not_string, call_runtime; | 2232 Label left_not_string, call_runtime; |
| 2250 | 2233 |
| 2251 Register left = r1; | 2234 Register left = r1; |
| 2252 Register right = r0; | 2235 Register right = r0; |
| 2253 | 2236 |
| 2254 // Check if left argument is a string. | 2237 // Check if left argument is a string. |
| 2255 __ JumpIfSmi(left, &left_not_string); | 2238 __ JumpIfSmi(left, &left_not_string); |
| 2256 __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE); | 2239 __ CompareObjectType(left, r2, r2, FIRST_NONSTRING_TYPE); |
| 2257 __ b(ge, &left_not_string); | 2240 __ b(ge, &left_not_string); |
| 2258 | 2241 |
| 2259 StringAddStub string_add_left_stub((StringAddFlags) | 2242 StringAddStub string_add_left_stub( |
| 2260 (ERECT_FRAME | NO_STRING_CHECK_LEFT_IN_STUB)); | 2243 (StringAddFlags)(STRING_ADD_CHECK_RIGHT | STRING_ADD_ERECT_FRAME)); |
| 2261 GenerateRegisterArgsPush(masm); | 2244 GenerateRegisterArgsPush(masm); |
| 2262 __ TailCallStub(&string_add_left_stub); | 2245 __ TailCallStub(&string_add_left_stub); |
| 2263 | 2246 |
| 2264 // Left operand is not a string, test right. | 2247 // Left operand is not a string, test right. |
| 2265 __ bind(&left_not_string); | 2248 __ bind(&left_not_string); |
| 2266 __ JumpIfSmi(right, &call_runtime); | 2249 __ JumpIfSmi(right, &call_runtime); |
| 2267 __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE); | 2250 __ CompareObjectType(right, r2, r2, FIRST_NONSTRING_TYPE); |
| 2268 __ b(ge, &call_runtime); | 2251 __ b(ge, &call_runtime); |
| 2269 | 2252 |
| 2270 StringAddStub string_add_right_stub((StringAddFlags) | 2253 StringAddStub string_add_right_stub( |
| 2271 (ERECT_FRAME | NO_STRING_CHECK_RIGHT_IN_STUB)); | 2254 (StringAddFlags)(STRING_ADD_CHECK_LEFT | STRING_ADD_ERECT_FRAME)); |
| 2272 GenerateRegisterArgsPush(masm); | 2255 GenerateRegisterArgsPush(masm); |
| 2273 __ TailCallStub(&string_add_right_stub); | 2256 __ TailCallStub(&string_add_right_stub); |
| 2274 | 2257 |
| 2275 // At least one argument is not a string. | 2258 // At least one argument is not a string. |
| 2276 __ bind(&call_runtime); | 2259 __ bind(&call_runtime); |
| 2277 } | 2260 } |
| 2278 | 2261 |
| 2279 | 2262 |
| 2280 void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, | 2263 void BinaryOpStub_GenerateHeapResultAllocation(MacroAssembler* masm, |
| 2281 Register result, | 2264 Register result, |
| (...skipping 3205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5487 | 5470 |
| 5488 // Stack on entry: | 5471 // Stack on entry: |
| 5489 // sp[0]: second argument (right). | 5472 // sp[0]: second argument (right). |
| 5490 // sp[4]: first argument (left). | 5473 // sp[4]: first argument (left). |
| 5491 | 5474 |
| 5492 // Load the two arguments. | 5475 // Load the two arguments. |
| 5493 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument. | 5476 __ ldr(r0, MemOperand(sp, 1 * kPointerSize)); // First argument. |
| 5494 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument. | 5477 __ ldr(r1, MemOperand(sp, 0 * kPointerSize)); // Second argument. |
| 5495 | 5478 |
| 5496 // Make sure that both arguments are strings if not known in advance. | 5479 // Make sure that both arguments are strings if not known in advance. |
| 5497 if ((flags_ & NO_STRING_ADD_FLAGS) != 0) { | 5480 // Otherwise, at least one of the arguments is definitely a string, |
| 5481 // and we convert the one that is not known to be a string. |
| 5482 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { |
| 5483 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT); |
| 5484 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT); |
| 5498 __ JumpIfEitherSmi(r0, r1, &call_runtime); | 5485 __ JumpIfEitherSmi(r0, r1, &call_runtime); |
| 5499 // Load instance types. | 5486 // Load instance types. |
| 5500 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | 5487 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 5501 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | 5488 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 5502 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 5489 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
| 5503 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | 5490 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
| 5504 STATIC_ASSERT(kStringTag == 0); | 5491 STATIC_ASSERT(kStringTag == 0); |
| 5505 // If either is not a string, go to runtime. | 5492 // If either is not a string, go to runtime. |
| 5506 __ tst(r4, Operand(kIsNotStringMask)); | 5493 __ tst(r4, Operand(kIsNotStringMask)); |
| 5507 __ tst(r5, Operand(kIsNotStringMask), eq); | 5494 __ tst(r5, Operand(kIsNotStringMask), eq); |
| 5508 __ b(ne, &call_runtime); | 5495 __ b(ne, &call_runtime); |
| 5509 } else { | 5496 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { |
| 5510 // Here at least one of the arguments is definitely a string. | 5497 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); |
| 5511 // We convert the one that is not known to be a string. | 5498 GenerateConvertArgument( |
| 5512 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { | 5499 masm, 1 * kPointerSize, r0, r2, r3, r4, r5, &call_builtin); |
| 5513 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); | 5500 builtin_id = Builtins::STRING_ADD_RIGHT; |
| 5514 GenerateConvertArgument( | 5501 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { |
| 5515 masm, 1 * kPointerSize, r0, r2, r3, r4, r5, &call_builtin); | 5502 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0); |
| 5516 builtin_id = Builtins::STRING_ADD_RIGHT; | 5503 GenerateConvertArgument( |
| 5517 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { | 5504 masm, 0 * kPointerSize, r1, r2, r3, r4, r5, &call_builtin); |
| 5518 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); | 5505 builtin_id = Builtins::STRING_ADD_LEFT; |
| 5519 GenerateConvertArgument( | |
| 5520 masm, 0 * kPointerSize, r1, r2, r3, r4, r5, &call_builtin); | |
| 5521 builtin_id = Builtins::STRING_ADD_LEFT; | |
| 5522 } | |
| 5523 } | 5506 } |
| 5524 | 5507 |
| 5525 // Both arguments are strings. | 5508 // Both arguments are strings. |
| 5526 // r0: first string | 5509 // r0: first string |
| 5527 // r1: second string | 5510 // r1: second string |
| 5528 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) | 5511 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
| 5529 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) | 5512 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
| 5530 { | 5513 { |
| 5531 Label strings_not_empty; | 5514 Label strings_not_empty; |
| 5532 // Check if either of the strings are empty. In that case return the other. | 5515 // Check if either of the strings are empty. In that case return the other. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 5560 Label string_add_flat_result, longer_than_two; | 5543 Label string_add_flat_result, longer_than_two; |
| 5561 // Adding two lengths can't overflow. | 5544 // Adding two lengths can't overflow. |
| 5562 STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2); | 5545 STATIC_ASSERT(String::kMaxLength < String::kMaxLength * 2); |
| 5563 __ add(r6, r2, Operand(r3)); | 5546 __ add(r6, r2, Operand(r3)); |
| 5564 // Use the string table when adding two one character strings, as it | 5547 // Use the string table when adding two one character strings, as it |
| 5565 // helps later optimizations to return a string here. | 5548 // helps later optimizations to return a string here. |
| 5566 __ cmp(r6, Operand(2)); | 5549 __ cmp(r6, Operand(2)); |
| 5567 __ b(ne, &longer_than_two); | 5550 __ b(ne, &longer_than_two); |
| 5568 | 5551 |
| 5569 // Check that both strings are non-external ASCII strings. | 5552 // Check that both strings are non-external ASCII strings. |
| 5570 if (flags_ != NO_STRING_ADD_FLAGS) { | 5553 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { |
| 5571 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | 5554 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 5572 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | 5555 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 5573 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 5556 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
| 5574 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | 5557 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
| 5575 } | 5558 } |
| 5576 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r7, | 5559 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r4, r5, r6, r7, |
| 5577 &call_runtime); | 5560 &call_runtime); |
| 5578 | 5561 |
| 5579 // Get the two characters forming the sub string. | 5562 // Get the two characters forming the sub string. |
| 5580 __ ldrb(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize)); | 5563 __ ldrb(r2, FieldMemOperand(r0, SeqOneByteString::kHeaderSize)); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 5608 __ b(lt, &string_add_flat_result); | 5591 __ b(lt, &string_add_flat_result); |
| 5609 // Handle exceptionally long strings in the runtime system. | 5592 // Handle exceptionally long strings in the runtime system. |
| 5610 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); | 5593 STATIC_ASSERT((String::kMaxLength & 0x80000000) == 0); |
| 5611 ASSERT(IsPowerOf2(String::kMaxLength + 1)); | 5594 ASSERT(IsPowerOf2(String::kMaxLength + 1)); |
| 5612 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. | 5595 // kMaxLength + 1 is representable as shifted literal, kMaxLength is not. |
| 5613 __ cmp(r6, Operand(String::kMaxLength + 1)); | 5596 __ cmp(r6, Operand(String::kMaxLength + 1)); |
| 5614 __ b(hs, &call_runtime); | 5597 __ b(hs, &call_runtime); |
| 5615 | 5598 |
| 5616 // If result is not supposed to be flat, allocate a cons string object. | 5599 // If result is not supposed to be flat, allocate a cons string object. |
| 5617 // If both strings are ASCII the result is an ASCII cons string. | 5600 // If both strings are ASCII the result is an ASCII cons string. |
| 5618 if (flags_ != NO_STRING_ADD_FLAGS) { | 5601 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { |
| 5619 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | 5602 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 5620 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | 5603 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 5621 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 5604 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
| 5622 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | 5605 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
| 5623 } | 5606 } |
| 5624 Label non_ascii, allocated, ascii_data; | 5607 Label non_ascii, allocated, ascii_data; |
| 5625 STATIC_ASSERT(kTwoByteStringTag == 0); | 5608 STATIC_ASSERT(kTwoByteStringTag == 0); |
| 5626 __ tst(r4, Operand(kStringEncodingMask)); | 5609 __ tst(r4, Operand(kStringEncodingMask)); |
| 5627 __ tst(r5, Operand(kStringEncodingMask), ne); | 5610 __ tst(r5, Operand(kStringEncodingMask), ne); |
| 5628 __ b(eq, &non_ascii); | 5611 __ b(eq, &non_ascii); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5691 // Locate the first characters' locations. | 5674 // Locate the first characters' locations. |
| 5692 // r0: first string | 5675 // r0: first string |
| 5693 // r1: second string | 5676 // r1: second string |
| 5694 // r2: length of first string | 5677 // r2: length of first string |
| 5695 // r3: length of second string | 5678 // r3: length of second string |
| 5696 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) | 5679 // r4: first string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
| 5697 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) | 5680 // r5: second string instance type (if flags_ == NO_STRING_ADD_FLAGS) |
| 5698 // r6: sum of lengths. | 5681 // r6: sum of lengths. |
| 5699 Label first_prepared, second_prepared; | 5682 Label first_prepared, second_prepared; |
| 5700 __ bind(&string_add_flat_result); | 5683 __ bind(&string_add_flat_result); |
| 5701 if (flags_ != NO_STRING_ADD_FLAGS) { | 5684 if ((flags_ & STRING_ADD_CHECK_BOTH) != STRING_ADD_CHECK_BOTH) { |
| 5702 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); | 5685 __ ldr(r4, FieldMemOperand(r0, HeapObject::kMapOffset)); |
| 5703 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); | 5686 __ ldr(r5, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| 5704 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); | 5687 __ ldrb(r4, FieldMemOperand(r4, Map::kInstanceTypeOffset)); |
| 5705 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); | 5688 __ ldrb(r5, FieldMemOperand(r5, Map::kInstanceTypeOffset)); |
| 5706 } | 5689 } |
| 5707 | 5690 |
| 5708 // Check whether both strings have same encoding | 5691 // Check whether both strings have same encoding |
| 5709 __ eor(r7, r4, Operand(r5)); | 5692 __ eor(r7, r4, Operand(r5)); |
| 5710 __ tst(r7, Operand(kStringEncodingMask)); | 5693 __ tst(r7, Operand(kStringEncodingMask)); |
| 5711 __ b(ne, &call_runtime); | 5694 __ b(ne, &call_runtime); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5779 // r6: first character of result. | 5762 // r6: first character of result. |
| 5780 StringHelper::GenerateCopyCharacters(masm, r6, r7, r2, r4, false); | 5763 StringHelper::GenerateCopyCharacters(masm, r6, r7, r2, r4, false); |
| 5781 // r6: next character of result. | 5764 // r6: next character of result. |
| 5782 StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, false); | 5765 StringHelper::GenerateCopyCharacters(masm, r6, r1, r3, r4, false); |
| 5783 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); | 5766 __ IncrementCounter(counters->string_add_native(), 1, r2, r3); |
| 5784 __ add(sp, sp, Operand(2 * kPointerSize)); | 5767 __ add(sp, sp, Operand(2 * kPointerSize)); |
| 5785 __ Ret(); | 5768 __ Ret(); |
| 5786 | 5769 |
| 5787 // Just jump to runtime to add the two strings. | 5770 // Just jump to runtime to add the two strings. |
| 5788 __ bind(&call_runtime); | 5771 __ bind(&call_runtime); |
| 5789 if ((flags_ & ERECT_FRAME) != 0) { | 5772 if ((flags_ & STRING_ADD_ERECT_FRAME) != 0) { |
| 5790 GenerateRegisterArgsPop(masm); | 5773 GenerateRegisterArgsPop(masm); |
| 5791 // Build a frame | 5774 // Build a frame |
| 5792 { | 5775 { |
| 5793 FrameScope scope(masm, StackFrame::INTERNAL); | 5776 FrameScope scope(masm, StackFrame::INTERNAL); |
| 5794 GenerateRegisterArgsPush(masm); | 5777 GenerateRegisterArgsPush(masm); |
| 5795 __ CallRuntime(Runtime::kStringAdd, 2); | 5778 __ CallRuntime(Runtime::kStringAdd, 2); |
| 5796 } | 5779 } |
| 5797 __ Ret(); | 5780 __ Ret(); |
| 5798 } else { | 5781 } else { |
| 5799 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 5782 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 5800 } | 5783 } |
| 5801 | 5784 |
| 5802 if (call_builtin.is_linked()) { | 5785 if (call_builtin.is_linked()) { |
| 5803 __ bind(&call_builtin); | 5786 __ bind(&call_builtin); |
| 5804 if ((flags_ & ERECT_FRAME) != 0) { | 5787 if ((flags_ & STRING_ADD_ERECT_FRAME) != 0) { |
| 5805 GenerateRegisterArgsPop(masm); | 5788 GenerateRegisterArgsPop(masm); |
| 5806 // Build a frame | 5789 // Build a frame |
| 5807 { | 5790 { |
| 5808 FrameScope scope(masm, StackFrame::INTERNAL); | 5791 FrameScope scope(masm, StackFrame::INTERNAL); |
| 5809 GenerateRegisterArgsPush(masm); | 5792 GenerateRegisterArgsPush(masm); |
| 5810 __ InvokeBuiltin(builtin_id, CALL_FUNCTION); | 5793 __ InvokeBuiltin(builtin_id, CALL_FUNCTION); |
| 5811 } | 5794 } |
| 5812 __ Ret(); | 5795 __ Ret(); |
| 5813 } else { | 5796 } else { |
| 5814 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | 5797 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5846 // Check the number to string cache. | 5829 // Check the number to string cache. |
| 5847 Label not_cached; | 5830 Label not_cached; |
| 5848 __ bind(¬_string); | 5831 __ bind(¬_string); |
| 5849 // Puts the cached result into scratch1. | 5832 // Puts the cached result into scratch1. |
| 5850 NumberToStringStub::GenerateLookupNumberStringCache(masm, | 5833 NumberToStringStub::GenerateLookupNumberStringCache(masm, |
| 5851 arg, | 5834 arg, |
| 5852 scratch1, | 5835 scratch1, |
| 5853 scratch2, | 5836 scratch2, |
| 5854 scratch3, | 5837 scratch3, |
| 5855 scratch4, | 5838 scratch4, |
| 5856 false, | |
| 5857 ¬_cached); | 5839 ¬_cached); |
| 5858 __ mov(arg, scratch1); | 5840 __ mov(arg, scratch1); |
| 5859 __ str(arg, MemOperand(sp, stack_offset)); | 5841 __ str(arg, MemOperand(sp, stack_offset)); |
| 5860 __ jmp(&done); | 5842 __ jmp(&done); |
| 5861 | 5843 |
| 5862 // Check if the argument is a safe string wrapper. | 5844 // Check if the argument is a safe string wrapper. |
| 5863 __ bind(¬_cached); | 5845 __ bind(¬_cached); |
| 5864 __ JumpIfSmi(arg, slow); | 5846 __ JumpIfSmi(arg, slow); |
| 5865 __ CompareObjectType( | 5847 __ CompareObjectType( |
| 5866 arg, scratch1, scratch2, JS_VALUE_TYPE); // map -> scratch1. | 5848 arg, scratch1, scratch2, JS_VALUE_TYPE); // map -> scratch1. |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5987 Register tmp2 = r3; | 5969 Register tmp2 = r3; |
| 5988 | 5970 |
| 5989 // Check that both operands are heap objects. | 5971 // Check that both operands are heap objects. |
| 5990 __ JumpIfEitherSmi(left, right, &miss); | 5972 __ JumpIfEitherSmi(left, right, &miss); |
| 5991 | 5973 |
| 5992 // Check that both operands are internalized strings. | 5974 // Check that both operands are internalized strings. |
| 5993 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); | 5975 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); |
| 5994 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | 5976 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); |
| 5995 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); | 5977 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); |
| 5996 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); | 5978 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); |
| 5997 STATIC_ASSERT(kInternalizedTag != 0); | 5979 STATIC_ASSERT(kInternalizedTag == 0 && kStringTag == 0); |
| 5998 | 5980 __ orr(tmp1, tmp1, Operand(tmp2)); |
| 5999 __ and_(tmp1, tmp1, Operand(kIsNotStringMask | kIsInternalizedMask)); | 5981 __ tst(tmp1, Operand(kIsNotStringMask | kIsNotInternalizedMask)); |
| 6000 __ cmp(tmp1, Operand(kInternalizedTag | kStringTag)); | |
| 6001 __ b(ne, &miss); | |
| 6002 | |
| 6003 __ and_(tmp2, tmp2, Operand(kIsNotStringMask | kIsInternalizedMask)); | |
| 6004 __ cmp(tmp2, Operand(kInternalizedTag | kStringTag)); | |
| 6005 __ b(ne, &miss); | 5982 __ b(ne, &miss); |
| 6006 | 5983 |
| 6007 // Internalized strings are compared by identity. | 5984 // Internalized strings are compared by identity. |
| 6008 __ cmp(left, right); | 5985 __ cmp(left, right); |
| 6009 // Make sure r0 is non-zero. At this point input operands are | 5986 // Make sure r0 is non-zero. At this point input operands are |
| 6010 // guaranteed to be non-zero. | 5987 // guaranteed to be non-zero. |
| 6011 ASSERT(right.is(r0)); | 5988 ASSERT(right.is(r0)); |
| 6012 STATIC_ASSERT(EQUAL == 0); | 5989 STATIC_ASSERT(EQUAL == 0); |
| 6013 STATIC_ASSERT(kSmiTag == 0); | 5990 STATIC_ASSERT(kSmiTag == 0); |
| 6014 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); | 5991 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 6028 Register left = r1; | 6005 Register left = r1; |
| 6029 Register right = r0; | 6006 Register right = r0; |
| 6030 Register tmp1 = r2; | 6007 Register tmp1 = r2; |
| 6031 Register tmp2 = r3; | 6008 Register tmp2 = r3; |
| 6032 | 6009 |
| 6033 // Check that both operands are heap objects. | 6010 // Check that both operands are heap objects. |
| 6034 __ JumpIfEitherSmi(left, right, &miss); | 6011 __ JumpIfEitherSmi(left, right, &miss); |
| 6035 | 6012 |
| 6036 // Check that both operands are unique names. This leaves the instance | 6013 // Check that both operands are unique names. This leaves the instance |
| 6037 // types loaded in tmp1 and tmp2. | 6014 // types loaded in tmp1 and tmp2. |
| 6038 STATIC_ASSERT(kInternalizedTag != 0); | |
| 6039 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); | 6015 __ ldr(tmp1, FieldMemOperand(left, HeapObject::kMapOffset)); |
| 6040 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | 6016 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); |
| 6041 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); | 6017 __ ldrb(tmp1, FieldMemOperand(tmp1, Map::kInstanceTypeOffset)); |
| 6042 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); | 6018 __ ldrb(tmp2, FieldMemOperand(tmp2, Map::kInstanceTypeOffset)); |
| 6043 | 6019 |
| 6044 __ JumpIfNotUniqueName(tmp1, &miss); | 6020 __ JumpIfNotUniqueName(tmp1, &miss); |
| 6045 __ JumpIfNotUniqueName(tmp2, &miss); | 6021 __ JumpIfNotUniqueName(tmp2, &miss); |
| 6046 | 6022 |
| 6047 // Unique names are compared by identity. | 6023 // Unique names are compared by identity. |
| 6048 __ cmp(left, right); | 6024 __ cmp(left, right); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6094 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); | 6070 __ mov(r0, Operand(Smi::FromInt(EQUAL)), LeaveCC, eq); |
| 6095 __ Ret(eq); | 6071 __ Ret(eq); |
| 6096 | 6072 |
| 6097 // Handle not identical strings. | 6073 // Handle not identical strings. |
| 6098 | 6074 |
| 6099 // Check that both strings are internalized strings. If they are, we're done | 6075 // Check that both strings are internalized strings. If they are, we're done |
| 6100 // because we already know they are not identical. We know they are both | 6076 // because we already know they are not identical. We know they are both |
| 6101 // strings. | 6077 // strings. |
| 6102 if (equality) { | 6078 if (equality) { |
| 6103 ASSERT(GetCondition() == eq); | 6079 ASSERT(GetCondition() == eq); |
| 6104 STATIC_ASSERT(kInternalizedTag != 0); | 6080 STATIC_ASSERT(kInternalizedTag == 0); |
| 6105 __ and_(tmp3, tmp1, Operand(tmp2)); | 6081 __ orr(tmp3, tmp1, Operand(tmp2)); |
| 6106 __ tst(tmp3, Operand(kIsInternalizedMask)); | 6082 __ tst(tmp3, Operand(kIsNotInternalizedMask)); |
| 6107 // Make sure r0 is non-zero. At this point input operands are | 6083 // Make sure r0 is non-zero. At this point input operands are |
| 6108 // guaranteed to be non-zero. | 6084 // guaranteed to be non-zero. |
| 6109 ASSERT(right.is(r0)); | 6085 ASSERT(right.is(r0)); |
| 6110 __ Ret(ne); | 6086 __ Ret(eq); |
| 6111 } | 6087 } |
| 6112 | 6088 |
| 6113 // Check that both strings are sequential ASCII. | 6089 // Check that both strings are sequential ASCII. |
| 6114 Label runtime; | 6090 Label runtime; |
| 6115 __ JumpIfBothInstanceTypesAreNotSequentialAscii( | 6091 __ JumpIfBothInstanceTypesAreNotSequentialAscii( |
| 6116 tmp1, tmp2, tmp3, tmp4, &runtime); | 6092 tmp1, tmp2, tmp3, tmp4, &runtime); |
| 6117 | 6093 |
| 6118 // Compare flat ASCII strings. Returns when done. | 6094 // Compare flat ASCII strings. Returns when done. |
| 6119 if (equality) { | 6095 if (equality) { |
| 6120 StringCompareStub::GenerateFlatAsciiStringEquals( | 6096 StringCompareStub::GenerateFlatAsciiStringEquals( |
| (...skipping 1078 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7199 __ bind(&fast_elements_case); | 7175 __ bind(&fast_elements_case); |
| 7200 GenerateCase(masm, FAST_ELEMENTS); | 7176 GenerateCase(masm, FAST_ELEMENTS); |
| 7201 } | 7177 } |
| 7202 | 7178 |
| 7203 | 7179 |
| 7204 #undef __ | 7180 #undef __ |
| 7205 | 7181 |
| 7206 } } // namespace v8::internal | 7182 } } // namespace v8::internal |
| 7207 | 7183 |
| 7208 #endif // V8_TARGET_ARCH_ARM | 7184 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |