| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 14 matching lines...) Expand all Loading... |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #if defined(V8_TARGET_ARCH_IA32) | 30 #if defined(V8_TARGET_ARCH_IA32) |
| 31 | 31 |
| 32 #include "code-stubs.h" | 32 #include "code-stubs.h" |
| 33 #include "bootstrapper.h" | 33 #include "bootstrapper.h" |
| 34 #include "jsregexp.h" | 34 #include "jsregexp.h" |
| 35 #include "isolate.h" |
| 35 #include "regexp-macro-assembler.h" | 36 #include "regexp-macro-assembler.h" |
| 36 | 37 |
| 37 namespace v8 { | 38 namespace v8 { |
| 38 namespace internal { | 39 namespace internal { |
| 39 | 40 |
| 40 #define __ ACCESS_MASM(masm) | 41 #define __ ACCESS_MASM(masm) |
| 41 | 42 |
| 42 void ToNumberStub::Generate(MacroAssembler* masm) { | 43 void ToNumberStub::Generate(MacroAssembler* masm) { |
| 43 // The ToNumber stub takes one argument in eax. | 44 // The ToNumber stub takes one argument in eax. |
| 44 NearLabel check_heap_number, call_builtin; | 45 NearLabel check_heap_number, call_builtin; |
| 45 __ test(eax, Immediate(kSmiTagMask)); | 46 __ test(eax, Immediate(kSmiTagMask)); |
| 46 __ j(not_zero, &check_heap_number); | 47 __ j(not_zero, &check_heap_number); |
| 47 __ ret(0); | 48 __ ret(0); |
| 48 | 49 |
| 49 __ bind(&check_heap_number); | 50 __ bind(&check_heap_number); |
| 50 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 51 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 51 __ cmp(Operand(ebx), Immediate(Factory::heap_number_map())); | 52 __ cmp(Operand(ebx), Immediate(FACTORY->heap_number_map())); |
| 52 __ j(not_equal, &call_builtin); | 53 __ j(not_equal, &call_builtin); |
| 53 __ ret(0); | 54 __ ret(0); |
| 54 | 55 |
| 55 __ bind(&call_builtin); | 56 __ bind(&call_builtin); |
| 56 __ pop(ecx); // Pop return address. | 57 __ pop(ecx); // Pop return address. |
| 57 __ push(eax); | 58 __ push(eax); |
| 58 __ push(ecx); // Push return address. | 59 __ push(ecx); // Push return address. |
| 59 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); | 60 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); |
| 60 } | 61 } |
| 61 | 62 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 75 | 76 |
| 76 // Compute the function map in the current global context and set that | 77 // Compute the function map in the current global context and set that |
| 77 // as the map of the allocated object. | 78 // as the map of the allocated object. |
| 78 __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 79 __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 79 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset)); | 80 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset)); |
| 80 __ mov(ecx, Operand(ecx, Context::SlotOffset(map_index))); | 81 __ mov(ecx, Operand(ecx, Context::SlotOffset(map_index))); |
| 81 __ mov(FieldOperand(eax, JSObject::kMapOffset), ecx); | 82 __ mov(FieldOperand(eax, JSObject::kMapOffset), ecx); |
| 82 | 83 |
| 83 // Initialize the rest of the function. We don't have to update the | 84 // Initialize the rest of the function. We don't have to update the |
| 84 // write barrier because the allocated object is in new space. | 85 // write barrier because the allocated object is in new space. |
| 85 __ mov(ebx, Immediate(Factory::empty_fixed_array())); | 86 __ mov(ebx, Immediate(FACTORY->empty_fixed_array())); |
| 86 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ebx); | 87 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ebx); |
| 87 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx); | 88 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx); |
| 88 __ mov(FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset), | 89 __ mov(FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset), |
| 89 Immediate(Factory::the_hole_value())); | 90 Immediate(FACTORY->the_hole_value())); |
| 90 __ mov(FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset), edx); | 91 __ mov(FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset), edx); |
| 91 __ mov(FieldOperand(eax, JSFunction::kContextOffset), esi); | 92 __ mov(FieldOperand(eax, JSFunction::kContextOffset), esi); |
| 92 __ mov(FieldOperand(eax, JSFunction::kLiteralsOffset), ebx); | 93 __ mov(FieldOperand(eax, JSFunction::kLiteralsOffset), ebx); |
| 93 __ mov(FieldOperand(eax, JSFunction::kNextFunctionLinkOffset), | 94 __ mov(FieldOperand(eax, JSFunction::kNextFunctionLinkOffset), |
| 94 Immediate(Factory::undefined_value())); | 95 Immediate(FACTORY->undefined_value())); |
| 95 | 96 |
| 96 // Initialize the code pointer in the function to be the one | 97 // Initialize the code pointer in the function to be the one |
| 97 // found in the shared function info object. | 98 // found in the shared function info object. |
| 98 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); | 99 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); |
| 99 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); | 100 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); |
| 100 __ mov(FieldOperand(eax, JSFunction::kCodeEntryOffset), edx); | 101 __ mov(FieldOperand(eax, JSFunction::kCodeEntryOffset), edx); |
| 101 | 102 |
| 102 // Return and remove the on-stack parameter. | 103 // Return and remove the on-stack parameter. |
| 103 __ ret(1 * kPointerSize); | 104 __ ret(1 * kPointerSize); |
| 104 | 105 |
| 105 // Create a new closure through the slower runtime call. | 106 // Create a new closure through the slower runtime call. |
| 106 __ bind(&gc); | 107 __ bind(&gc); |
| 107 __ pop(ecx); // Temporarily remove return address. | 108 __ pop(ecx); // Temporarily remove return address. |
| 108 __ pop(edx); | 109 __ pop(edx); |
| 109 __ push(esi); | 110 __ push(esi); |
| 110 __ push(edx); | 111 __ push(edx); |
| 111 __ push(Immediate(Factory::false_value())); | 112 __ push(Immediate(FACTORY->false_value())); |
| 112 __ push(ecx); // Restore return address. | 113 __ push(ecx); // Restore return address. |
| 113 __ TailCallRuntime(Runtime::kNewClosure, 3, 1); | 114 __ TailCallRuntime(Runtime::kNewClosure, 3, 1); |
| 114 } | 115 } |
| 115 | 116 |
| 116 | 117 |
| 117 void FastNewContextStub::Generate(MacroAssembler* masm) { | 118 void FastNewContextStub::Generate(MacroAssembler* masm) { |
| 118 // Try to allocate the context in new space. | 119 // Try to allocate the context in new space. |
| 119 Label gc; | 120 Label gc; |
| 120 int length = slots_ + Context::MIN_CONTEXT_SLOTS; | 121 int length = slots_ + Context::MIN_CONTEXT_SLOTS; |
| 121 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, | 122 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, |
| 122 eax, ebx, ecx, &gc, TAG_OBJECT); | 123 eax, ebx, ecx, &gc, TAG_OBJECT); |
| 123 | 124 |
| 124 // Get the function from the stack. | 125 // Get the function from the stack. |
| 125 __ mov(ecx, Operand(esp, 1 * kPointerSize)); | 126 __ mov(ecx, Operand(esp, 1 * kPointerSize)); |
| 126 | 127 |
| 127 // Setup the object header. | 128 // Setup the object header. |
| 128 __ mov(FieldOperand(eax, HeapObject::kMapOffset), Factory::context_map()); | 129 __ mov(FieldOperand(eax, HeapObject::kMapOffset), FACTORY->context_map()); |
| 129 __ mov(FieldOperand(eax, Context::kLengthOffset), | 130 __ mov(FieldOperand(eax, Context::kLengthOffset), |
| 130 Immediate(Smi::FromInt(length))); | 131 Immediate(Smi::FromInt(length))); |
| 131 | 132 |
| 132 // Setup the fixed slots. | 133 // Setup the fixed slots. |
| 133 __ Set(ebx, Immediate(0)); // Set to NULL. | 134 __ Set(ebx, Immediate(0)); // Set to NULL. |
| 134 __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx); | 135 __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx); |
| 135 __ mov(Operand(eax, Context::SlotOffset(Context::FCONTEXT_INDEX)), eax); | 136 __ mov(Operand(eax, Context::SlotOffset(Context::FCONTEXT_INDEX)), eax); |
| 136 __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), ebx); | 137 __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), ebx); |
| 137 __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx); | 138 __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx); |
| 138 | 139 |
| 139 // Copy the global object from the surrounding context. We go through the | 140 // Copy the global object from the surrounding context. We go through the |
| 140 // context in the function (ecx) to match the allocation behavior we have | 141 // context in the function (ecx) to match the allocation behavior we have |
| 141 // in the runtime system (see Heap::AllocateFunctionContext). | 142 // in the runtime system (see Heap::AllocateFunctionContext). |
| 142 __ mov(ebx, FieldOperand(ecx, JSFunction::kContextOffset)); | 143 __ mov(ebx, FieldOperand(ecx, JSFunction::kContextOffset)); |
| 143 __ mov(ebx, Operand(ebx, Context::SlotOffset(Context::GLOBAL_INDEX))); | 144 __ mov(ebx, Operand(ebx, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 144 __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); | 145 __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); |
| 145 | 146 |
| 146 // Initialize the rest of the slots to undefined. | 147 // Initialize the rest of the slots to undefined. |
| 147 __ mov(ebx, Factory::undefined_value()); | 148 __ mov(ebx, FACTORY->undefined_value()); |
| 148 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { | 149 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { |
| 149 __ mov(Operand(eax, Context::SlotOffset(i)), ebx); | 150 __ mov(Operand(eax, Context::SlotOffset(i)), ebx); |
| 150 } | 151 } |
| 151 | 152 |
| 152 // Return and remove the on-stack parameter. | 153 // Return and remove the on-stack parameter. |
| 153 __ mov(esi, Operand(eax)); | 154 __ mov(esi, Operand(eax)); |
| 154 __ ret(1 * kPointerSize); | 155 __ ret(1 * kPointerSize); |
| 155 | 156 |
| 156 // Need to collect. Call into runtime system. | 157 // Need to collect. Call into runtime system. |
| 157 __ bind(&gc); | 158 __ bind(&gc); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 173 // Load boilerplate object into ecx and check if we need to create a | 174 // Load boilerplate object into ecx and check if we need to create a |
| 174 // boilerplate. | 175 // boilerplate. |
| 175 Label slow_case; | 176 Label slow_case; |
| 176 __ mov(ecx, Operand(esp, 3 * kPointerSize)); | 177 __ mov(ecx, Operand(esp, 3 * kPointerSize)); |
| 177 __ mov(eax, Operand(esp, 2 * kPointerSize)); | 178 __ mov(eax, Operand(esp, 2 * kPointerSize)); |
| 178 STATIC_ASSERT(kPointerSize == 4); | 179 STATIC_ASSERT(kPointerSize == 4); |
| 179 STATIC_ASSERT(kSmiTagSize == 1); | 180 STATIC_ASSERT(kSmiTagSize == 1); |
| 180 STATIC_ASSERT(kSmiTag == 0); | 181 STATIC_ASSERT(kSmiTag == 0); |
| 181 __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size, | 182 __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size, |
| 182 FixedArray::kHeaderSize)); | 183 FixedArray::kHeaderSize)); |
| 183 __ cmp(ecx, Factory::undefined_value()); | 184 __ cmp(ecx, FACTORY->undefined_value()); |
| 184 __ j(equal, &slow_case); | 185 __ j(equal, &slow_case); |
| 185 | 186 |
| 186 if (FLAG_debug_code) { | 187 if (FLAG_debug_code) { |
| 187 const char* message; | 188 const char* message; |
| 188 Handle<Map> expected_map; | 189 Handle<Map> expected_map; |
| 189 if (mode_ == CLONE_ELEMENTS) { | 190 if (mode_ == CLONE_ELEMENTS) { |
| 190 message = "Expected (writable) fixed array"; | 191 message = "Expected (writable) fixed array"; |
| 191 expected_map = Factory::fixed_array_map(); | 192 expected_map = FACTORY->fixed_array_map(); |
| 192 } else { | 193 } else { |
| 193 ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS); | 194 ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS); |
| 194 message = "Expected copy-on-write fixed array"; | 195 message = "Expected copy-on-write fixed array"; |
| 195 expected_map = Factory::fixed_cow_array_map(); | 196 expected_map = FACTORY->fixed_cow_array_map(); |
| 196 } | 197 } |
| 197 __ push(ecx); | 198 __ push(ecx); |
| 198 __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); | 199 __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); |
| 199 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map); | 200 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map); |
| 200 __ Assert(equal, message); | 201 __ Assert(equal, message); |
| 201 __ pop(ecx); | 202 __ pop(ecx); |
| 202 } | 203 } |
| 203 | 204 |
| 204 // Allocate both the JS array and the elements array in one big | 205 // Allocate both the JS array and the elements array in one big |
| 205 // allocation. This avoids multiple limit checks. | 206 // allocation. This avoids multiple limit checks. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 234 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); | 235 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
| 235 } | 236 } |
| 236 | 237 |
| 237 | 238 |
| 238 // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined). | 239 // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined). |
| 239 void ToBooleanStub::Generate(MacroAssembler* masm) { | 240 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 240 NearLabel false_result, true_result, not_string; | 241 NearLabel false_result, true_result, not_string; |
| 241 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 242 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 242 | 243 |
| 243 // 'null' => false. | 244 // 'null' => false. |
| 244 __ cmp(eax, Factory::null_value()); | 245 __ cmp(eax, FACTORY->null_value()); |
| 245 __ j(equal, &false_result); | 246 __ j(equal, &false_result); |
| 246 | 247 |
| 247 // Get the map and type of the heap object. | 248 // Get the map and type of the heap object. |
| 248 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 249 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 249 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); | 250 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); |
| 250 | 251 |
| 251 // Undetectable => false. | 252 // Undetectable => false. |
| 252 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), | 253 __ test_b(FieldOperand(edx, Map::kBitFieldOffset), |
| 253 1 << Map::kIsUndetectable); | 254 1 << Map::kIsUndetectable); |
| 254 __ j(not_zero, &false_result); | 255 __ j(not_zero, &false_result); |
| 255 | 256 |
| 256 // JavaScript object => true. | 257 // JavaScript object => true. |
| 257 __ CmpInstanceType(edx, FIRST_JS_OBJECT_TYPE); | 258 __ CmpInstanceType(edx, FIRST_JS_OBJECT_TYPE); |
| 258 __ j(above_equal, &true_result); | 259 __ j(above_equal, &true_result); |
| 259 | 260 |
| 260 // String value => false iff empty. | 261 // String value => false iff empty. |
| 261 __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE); | 262 __ CmpInstanceType(edx, FIRST_NONSTRING_TYPE); |
| 262 __ j(above_equal, ¬_string); | 263 __ j(above_equal, ¬_string); |
| 263 STATIC_ASSERT(kSmiTag == 0); | 264 STATIC_ASSERT(kSmiTag == 0); |
| 264 __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0)); | 265 __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0)); |
| 265 __ j(zero, &false_result); | 266 __ j(zero, &false_result); |
| 266 __ jmp(&true_result); | 267 __ jmp(&true_result); |
| 267 | 268 |
| 268 __ bind(¬_string); | 269 __ bind(¬_string); |
| 269 // HeapNumber => false iff +0, -0, or NaN. | 270 // HeapNumber => false iff +0, -0, or NaN. |
| 270 __ cmp(edx, Factory::heap_number_map()); | 271 __ cmp(edx, FACTORY->heap_number_map()); |
| 271 __ j(not_equal, &true_result); | 272 __ j(not_equal, &true_result); |
| 272 __ fldz(); | 273 __ fldz(); |
| 273 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 274 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 274 __ FCmp(); | 275 __ FCmp(); |
| 275 __ j(zero, &false_result); | 276 __ j(zero, &false_result); |
| 276 // Fall through to |true_result|. | 277 // Fall through to |true_result|. |
| 277 | 278 |
| 278 // Return 1/0 for true/false in eax. | 279 // Return 1/0 for true/false in eax. |
| 279 __ bind(&true_result); | 280 __ bind(&true_result); |
| 280 __ mov(eax, 1); | 281 __ mov(eax, 1); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 293 if (save_doubles_ == kSaveFPRegs) { | 294 if (save_doubles_ == kSaveFPRegs) { |
| 294 CpuFeatures::Scope scope(SSE2); | 295 CpuFeatures::Scope scope(SSE2); |
| 295 __ sub(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters)); | 296 __ sub(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters)); |
| 296 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { | 297 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { |
| 297 XMMRegister reg = XMMRegister::from_code(i); | 298 XMMRegister reg = XMMRegister::from_code(i); |
| 298 __ movdbl(Operand(esp, i * kDoubleSize), reg); | 299 __ movdbl(Operand(esp, i * kDoubleSize), reg); |
| 299 } | 300 } |
| 300 } | 301 } |
| 301 const int argument_count = 0; | 302 const int argument_count = 0; |
| 302 __ PrepareCallCFunction(argument_count, ecx); | 303 __ PrepareCallCFunction(argument_count, ecx); |
| 303 ExternalReference store_buffer_overflow = | 304 __ CallCFunction(ExternalReference::store_buffer_overflow_function(), |
| 304 ExternalReference(Runtime::FunctionForId(Runtime::kStoreBufferOverflow)); | 305 argument_count); |
| 305 __ CallCFunction(store_buffer_overflow, argument_count); | |
| 306 if (save_doubles_ == kSaveFPRegs) { | 306 if (save_doubles_ == kSaveFPRegs) { |
| 307 CpuFeatures::Scope scope(SSE2); | 307 CpuFeatures::Scope scope(SSE2); |
| 308 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { | 308 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { |
| 309 XMMRegister reg = XMMRegister::from_code(i); | 309 XMMRegister reg = XMMRegister::from_code(i); |
| 310 __ movdbl(reg, Operand(esp, i * kDoubleSize)); | 310 __ movdbl(reg, Operand(esp, i * kDoubleSize)); |
| 311 } | 311 } |
| 312 __ add(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters)); | 312 __ add(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters)); |
| 313 } | 313 } |
| 314 __ popad(); | 314 __ popad(); |
| 315 __ ret(0); | 315 __ ret(0); |
| 316 } | 316 } |
| 317 | 317 |
| 318 | 318 |
| 319 const char* GenericBinaryOpStub::GetName() { | 319 const char* GenericBinaryOpStub::GetName() { |
| 320 if (name_ != NULL) return name_; | 320 if (name_ != NULL) return name_; |
| 321 const int kMaxNameLength = 100; | 321 const int kMaxNameLength = 100; |
| 322 name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); | 322 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( |
| 323 kMaxNameLength); |
| 323 if (name_ == NULL) return "OOM"; | 324 if (name_ == NULL) return "OOM"; |
| 324 const char* op_name = Token::Name(op_); | 325 const char* op_name = Token::Name(op_); |
| 325 const char* overwrite_name; | 326 const char* overwrite_name; |
| 326 switch (mode_) { | 327 switch (mode_) { |
| 327 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 328 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 328 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 329 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
| 329 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 330 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
| 330 default: overwrite_name = "UnknownOverwrite"; break; | 331 default: overwrite_name = "UnknownOverwrite"; break; |
| 331 } | 332 } |
| 332 | 333 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 } | 387 } |
| 387 } else { | 388 } else { |
| 388 // Order of moves is not important. | 389 // Order of moves is not important. |
| 389 __ mov(left_arg, left); | 390 __ mov(left_arg, left); |
| 390 __ mov(right_arg, right); | 391 __ mov(right_arg, right); |
| 391 } | 392 } |
| 392 } | 393 } |
| 393 | 394 |
| 394 // Update flags to indicate that arguments are in registers. | 395 // Update flags to indicate that arguments are in registers. |
| 395 SetArgsInRegisters(); | 396 SetArgsInRegisters(); |
| 396 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 397 __ IncrementCounter(COUNTERS->generic_binary_stub_calls_regs(), 1); |
| 397 } | 398 } |
| 398 | 399 |
| 399 // Call the stub. | 400 // Call the stub. |
| 400 __ CallStub(this); | 401 __ CallStub(this); |
| 401 } | 402 } |
| 402 | 403 |
| 403 | 404 |
| 404 void GenericBinaryOpStub::GenerateCall( | 405 void GenericBinaryOpStub::GenerateCall( |
| 405 MacroAssembler* masm, | 406 MacroAssembler* masm, |
| 406 Register left, | 407 Register left, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 422 // For non-commutative operations, left and right_arg might be | 423 // For non-commutative operations, left and right_arg might be |
| 423 // the same register. Therefore, the order of the moves is | 424 // the same register. Therefore, the order of the moves is |
| 424 // important here in order to not overwrite left before moving | 425 // important here in order to not overwrite left before moving |
| 425 // it to left_arg. | 426 // it to left_arg. |
| 426 __ mov(left_arg, left); | 427 __ mov(left_arg, left); |
| 427 __ mov(right_arg, Immediate(right)); | 428 __ mov(right_arg, Immediate(right)); |
| 428 } | 429 } |
| 429 | 430 |
| 430 // Update flags to indicate that arguments are in registers. | 431 // Update flags to indicate that arguments are in registers. |
| 431 SetArgsInRegisters(); | 432 SetArgsInRegisters(); |
| 432 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 433 __ IncrementCounter(COUNTERS->generic_binary_stub_calls_regs(), 1); |
| 433 } | 434 } |
| 434 | 435 |
| 435 // Call the stub. | 436 // Call the stub. |
| 436 __ CallStub(this); | 437 __ CallStub(this); |
| 437 } | 438 } |
| 438 | 439 |
| 439 | 440 |
| 440 void GenericBinaryOpStub::GenerateCall( | 441 void GenericBinaryOpStub::GenerateCall( |
| 441 MacroAssembler* masm, | 442 MacroAssembler* masm, |
| 442 Smi* left, | 443 Smi* left, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 457 } else { | 458 } else { |
| 458 // For non-commutative operations, right and left_arg might be | 459 // For non-commutative operations, right and left_arg might be |
| 459 // the same register. Therefore, the order of the moves is | 460 // the same register. Therefore, the order of the moves is |
| 460 // important here in order to not overwrite right before moving | 461 // important here in order to not overwrite right before moving |
| 461 // it to right_arg. | 462 // it to right_arg. |
| 462 __ mov(right_arg, right); | 463 __ mov(right_arg, right); |
| 463 __ mov(left_arg, Immediate(left)); | 464 __ mov(left_arg, Immediate(left)); |
| 464 } | 465 } |
| 465 // Update flags to indicate that arguments are in registers. | 466 // Update flags to indicate that arguments are in registers. |
| 466 SetArgsInRegisters(); | 467 SetArgsInRegisters(); |
| 467 __ IncrementCounter(&Counters::generic_binary_stub_calls_regs, 1); | 468 __ IncrementCounter(COUNTERS->generic_binary_stub_calls_regs(), 1); |
| 468 } | 469 } |
| 469 | 470 |
| 470 // Call the stub. | 471 // Call the stub. |
| 471 __ CallStub(this); | 472 __ CallStub(this); |
| 472 } | 473 } |
| 473 | 474 |
| 474 | 475 |
| 475 class FloatingPointHelper : public AllStatic { | 476 class FloatingPointHelper : public AllStatic { |
| 476 public: | 477 public: |
| 477 | 478 |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 785 // overflowed the smi range). | 786 // overflowed the smi range). |
| 786 switch (op_) { | 787 switch (op_) { |
| 787 case Token::SHL: { | 788 case Token::SHL: { |
| 788 Comment perform_float(masm, "-- Perform float operation on smis"); | 789 Comment perform_float(masm, "-- Perform float operation on smis"); |
| 789 __ bind(&use_fp_on_smis); | 790 __ bind(&use_fp_on_smis); |
| 790 if (runtime_operands_type_ != BinaryOpIC::UNINIT_OR_SMI) { | 791 if (runtime_operands_type_ != BinaryOpIC::UNINIT_OR_SMI) { |
| 791 // Result we want is in left == edx, so we can put the allocated heap | 792 // Result we want is in left == edx, so we can put the allocated heap |
| 792 // number in eax. | 793 // number in eax. |
| 793 __ AllocateHeapNumber(eax, ecx, ebx, slow); | 794 __ AllocateHeapNumber(eax, ecx, ebx, slow); |
| 794 // Store the result in the HeapNumber and return. | 795 // Store the result in the HeapNumber and return. |
| 795 if (CpuFeatures::IsSupported(SSE2)) { | 796 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 796 CpuFeatures::Scope use_sse2(SSE2); | 797 CpuFeatures::Scope use_sse2(SSE2); |
| 797 __ cvtsi2sd(xmm0, Operand(left)); | 798 __ cvtsi2sd(xmm0, Operand(left)); |
| 798 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 799 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 799 } else { | 800 } else { |
| 800 // It's OK to overwrite the right argument on the stack because we | 801 // It's OK to overwrite the right argument on the stack because we |
| 801 // are about to return. | 802 // are about to return. |
| 802 __ mov(Operand(esp, 1 * kPointerSize), left); | 803 __ mov(Operand(esp, 1 * kPointerSize), left); |
| 803 __ fild_s(Operand(esp, 1 * kPointerSize)); | 804 __ fild_s(Operand(esp, 1 * kPointerSize)); |
| 804 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 805 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 805 } | 806 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 835 // Left was clobbered but a copy is in edi. Right is in ebx for | 836 // Left was clobbered but a copy is in edi. Right is in ebx for |
| 836 // division. | 837 // division. |
| 837 __ mov(edx, edi); | 838 __ mov(edx, edi); |
| 838 __ mov(eax, right); | 839 __ mov(eax, right); |
| 839 break; | 840 break; |
| 840 default: UNREACHABLE(); | 841 default: UNREACHABLE(); |
| 841 break; | 842 break; |
| 842 } | 843 } |
| 843 if (runtime_operands_type_ != BinaryOpIC::UNINIT_OR_SMI) { | 844 if (runtime_operands_type_ != BinaryOpIC::UNINIT_OR_SMI) { |
| 844 __ AllocateHeapNumber(ecx, ebx, no_reg, slow); | 845 __ AllocateHeapNumber(ecx, ebx, no_reg, slow); |
| 845 if (CpuFeatures::IsSupported(SSE2)) { | 846 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 846 CpuFeatures::Scope use_sse2(SSE2); | 847 CpuFeatures::Scope use_sse2(SSE2); |
| 847 FloatingPointHelper::LoadSSE2Smis(masm, ebx); | 848 FloatingPointHelper::LoadSSE2Smis(masm, ebx); |
| 848 switch (op_) { | 849 switch (op_) { |
| 849 case Token::ADD: __ addsd(xmm0, xmm1); break; | 850 case Token::ADD: __ addsd(xmm0, xmm1); break; |
| 850 case Token::SUB: __ subsd(xmm0, xmm1); break; | 851 case Token::SUB: __ subsd(xmm0, xmm1); break; |
| 851 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 852 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| 852 case Token::DIV: __ divsd(xmm0, xmm1); break; | 853 case Token::DIV: __ divsd(xmm0, xmm1); break; |
| 853 default: UNREACHABLE(); | 854 default: UNREACHABLE(); |
| 854 } | 855 } |
| 855 __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); | 856 __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 900 | 901 |
| 901 default: | 902 default: |
| 902 break; | 903 break; |
| 903 } | 904 } |
| 904 } | 905 } |
| 905 | 906 |
| 906 | 907 |
| 907 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { | 908 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { |
| 908 Label call_runtime; | 909 Label call_runtime; |
| 909 | 910 |
| 910 __ IncrementCounter(&Counters::generic_binary_stub_calls, 1); | 911 __ IncrementCounter(COUNTERS->generic_binary_stub_calls(), 1); |
| 911 | 912 |
| 912 if (runtime_operands_type_ == BinaryOpIC::UNINIT_OR_SMI) { | 913 if (runtime_operands_type_ == BinaryOpIC::UNINIT_OR_SMI) { |
| 913 Label slow; | 914 Label slow; |
| 914 if (ShouldGenerateSmiCode()) GenerateSmiCode(masm, &slow); | 915 if (ShouldGenerateSmiCode()) GenerateSmiCode(masm, &slow); |
| 915 __ bind(&slow); | 916 __ bind(&slow); |
| 916 GenerateTypeTransition(masm); | 917 GenerateTypeTransition(masm); |
| 917 } | 918 } |
| 918 | 919 |
| 919 // Generate fast case smi code if requested. This flag is set when the fast | 920 // Generate fast case smi code if requested. This flag is set when the fast |
| 920 // case smi code is not generated by the caller. Generating it here will speed | 921 // case smi code is not generated by the caller. Generating it here will speed |
| (...skipping 18 matching lines...) Expand all Loading... |
| 939 // Execution reaches this point when the first non-smi argument occurs | 940 // Execution reaches this point when the first non-smi argument occurs |
| 940 // (and only if smi code is generated). This is the right moment to | 941 // (and only if smi code is generated). This is the right moment to |
| 941 // patch to HEAP_NUMBERS state. The transition is attempted only for | 942 // patch to HEAP_NUMBERS state. The transition is attempted only for |
| 942 // the four basic operations. The stub stays in the DEFAULT state | 943 // the four basic operations. The stub stays in the DEFAULT state |
| 943 // forever for all other operations (also if smi code is skipped). | 944 // forever for all other operations (also if smi code is skipped). |
| 944 GenerateTypeTransition(masm); | 945 GenerateTypeTransition(masm); |
| 945 break; | 946 break; |
| 946 } | 947 } |
| 947 | 948 |
| 948 Label not_floats; | 949 Label not_floats; |
| 949 if (CpuFeatures::IsSupported(SSE2)) { | 950 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 950 CpuFeatures::Scope use_sse2(SSE2); | 951 CpuFeatures::Scope use_sse2(SSE2); |
| 951 if (static_operands_type_.IsNumber()) { | 952 if (static_operands_type_.IsNumber()) { |
| 952 if (FLAG_debug_code) { | 953 if (FLAG_debug_code) { |
| 953 // Assert at runtime that inputs are only numbers. | 954 // Assert at runtime that inputs are only numbers. |
| 954 __ AbortIfNotNumber(edx); | 955 __ AbortIfNotNumber(edx); |
| 955 __ AbortIfNotNumber(eax); | 956 __ AbortIfNotNumber(eax); |
| 956 } | 957 } |
| 957 if (static_operands_type_.IsSmi()) { | 958 if (static_operands_type_.IsSmi()) { |
| 958 if (FLAG_debug_code) { | 959 if (FLAG_debug_code) { |
| 959 __ AbortIfNotSmi(edx); | 960 __ AbortIfNotSmi(edx); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1073 __ test(eax, Immediate(kSmiTagMask)); | 1074 __ test(eax, Immediate(kSmiTagMask)); |
| 1074 __ j(not_zero, &skip_allocation, not_taken); | 1075 __ j(not_zero, &skip_allocation, not_taken); |
| 1075 // Fall through! | 1076 // Fall through! |
| 1076 case NO_OVERWRITE: | 1077 case NO_OVERWRITE: |
| 1077 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | 1078 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
| 1078 __ bind(&skip_allocation); | 1079 __ bind(&skip_allocation); |
| 1079 break; | 1080 break; |
| 1080 default: UNREACHABLE(); | 1081 default: UNREACHABLE(); |
| 1081 } | 1082 } |
| 1082 // Store the result in the HeapNumber and return. | 1083 // Store the result in the HeapNumber and return. |
| 1083 if (CpuFeatures::IsSupported(SSE2)) { | 1084 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 1084 CpuFeatures::Scope use_sse2(SSE2); | 1085 CpuFeatures::Scope use_sse2(SSE2); |
| 1085 __ cvtsi2sd(xmm0, Operand(ebx)); | 1086 __ cvtsi2sd(xmm0, Operand(ebx)); |
| 1086 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 1087 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 1087 } else { | 1088 } else { |
| 1088 __ mov(Operand(esp, 1 * kPointerSize), ebx); | 1089 __ mov(Operand(esp, 1 * kPointerSize), ebx); |
| 1089 __ fild_s(Operand(esp, 1 * kPointerSize)); | 1090 __ fild_s(Operand(esp, 1 * kPointerSize)); |
| 1090 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 1091 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 1091 } | 1092 } |
| 1092 GenerateReturn(masm); | 1093 GenerateReturn(masm); |
| 1093 } | 1094 } |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1385 break; | 1386 break; |
| 1386 default: | 1387 default: |
| 1387 UNREACHABLE(); | 1388 UNREACHABLE(); |
| 1388 } | 1389 } |
| 1389 } | 1390 } |
| 1390 | 1391 |
| 1391 | 1392 |
| 1392 const char* TypeRecordingBinaryOpStub::GetName() { | 1393 const char* TypeRecordingBinaryOpStub::GetName() { |
| 1393 if (name_ != NULL) return name_; | 1394 if (name_ != NULL) return name_; |
| 1394 const int kMaxNameLength = 100; | 1395 const int kMaxNameLength = 100; |
| 1395 name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); | 1396 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( |
| 1397 kMaxNameLength); |
| 1396 if (name_ == NULL) return "OOM"; | 1398 if (name_ == NULL) return "OOM"; |
| 1397 const char* op_name = Token::Name(op_); | 1399 const char* op_name = Token::Name(op_); |
| 1398 const char* overwrite_name; | 1400 const char* overwrite_name; |
| 1399 switch (mode_) { | 1401 switch (mode_) { |
| 1400 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 1402 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 1401 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 1403 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
| 1402 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 1404 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
| 1403 default: overwrite_name = "UnknownOverwrite"; break; | 1405 default: overwrite_name = "UnknownOverwrite"; break; |
| 1404 } | 1406 } |
| 1405 | 1407 |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1667 } else { | 1669 } else { |
| 1668 ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS); | 1670 ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS); |
| 1669 switch (op_) { | 1671 switch (op_) { |
| 1670 case Token::SHL: { | 1672 case Token::SHL: { |
| 1671 Comment perform_float(masm, "-- Perform float operation on smis"); | 1673 Comment perform_float(masm, "-- Perform float operation on smis"); |
| 1672 __ bind(&use_fp_on_smis); | 1674 __ bind(&use_fp_on_smis); |
| 1673 // Result we want is in left == edx, so we can put the allocated heap | 1675 // Result we want is in left == edx, so we can put the allocated heap |
| 1674 // number in eax. | 1676 // number in eax. |
| 1675 __ AllocateHeapNumber(eax, ecx, ebx, slow); | 1677 __ AllocateHeapNumber(eax, ecx, ebx, slow); |
| 1676 // Store the result in the HeapNumber and return. | 1678 // Store the result in the HeapNumber and return. |
| 1677 if (CpuFeatures::IsSupported(SSE2)) { | 1679 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 1678 CpuFeatures::Scope use_sse2(SSE2); | 1680 CpuFeatures::Scope use_sse2(SSE2); |
| 1679 __ cvtsi2sd(xmm0, Operand(left)); | 1681 __ cvtsi2sd(xmm0, Operand(left)); |
| 1680 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 1682 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 1681 } else { | 1683 } else { |
| 1682 // It's OK to overwrite the right argument on the stack because we | 1684 // It's OK to overwrite the right argument on the stack because we |
| 1683 // are about to return. | 1685 // are about to return. |
| 1684 __ mov(Operand(esp, 1 * kPointerSize), left); | 1686 __ mov(Operand(esp, 1 * kPointerSize), left); |
| 1685 __ fild_s(Operand(esp, 1 * kPointerSize)); | 1687 __ fild_s(Operand(esp, 1 * kPointerSize)); |
| 1686 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 1688 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 1687 } | 1689 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1712 case Token::DIV: | 1714 case Token::DIV: |
| 1713 // Left was clobbered but a copy is in edi. Right is in ebx for | 1715 // Left was clobbered but a copy is in edi. Right is in ebx for |
| 1714 // division. | 1716 // division. |
| 1715 __ mov(edx, edi); | 1717 __ mov(edx, edi); |
| 1716 __ mov(eax, right); | 1718 __ mov(eax, right); |
| 1717 break; | 1719 break; |
| 1718 default: UNREACHABLE(); | 1720 default: UNREACHABLE(); |
| 1719 break; | 1721 break; |
| 1720 } | 1722 } |
| 1721 __ AllocateHeapNumber(ecx, ebx, no_reg, slow); | 1723 __ AllocateHeapNumber(ecx, ebx, no_reg, slow); |
| 1722 if (CpuFeatures::IsSupported(SSE2)) { | 1724 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 1723 CpuFeatures::Scope use_sse2(SSE2); | 1725 CpuFeatures::Scope use_sse2(SSE2); |
| 1724 FloatingPointHelper::LoadSSE2Smis(masm, ebx); | 1726 FloatingPointHelper::LoadSSE2Smis(masm, ebx); |
| 1725 switch (op_) { | 1727 switch (op_) { |
| 1726 case Token::ADD: __ addsd(xmm0, xmm1); break; | 1728 case Token::ADD: __ addsd(xmm0, xmm1); break; |
| 1727 case Token::SUB: __ subsd(xmm0, xmm1); break; | 1729 case Token::SUB: __ subsd(xmm0, xmm1); break; |
| 1728 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 1730 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| 1729 case Token::DIV: __ divsd(xmm0, xmm1); break; | 1731 case Token::DIV: __ divsd(xmm0, xmm1); break; |
| 1730 default: UNREACHABLE(); | 1732 default: UNREACHABLE(); |
| 1731 } | 1733 } |
| 1732 __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); | 1734 __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1844 ASSERT(operands_type_ == TRBinaryOpIC::INT32); | 1846 ASSERT(operands_type_ == TRBinaryOpIC::INT32); |
| 1845 | 1847 |
| 1846 // Floating point case. | 1848 // Floating point case. |
| 1847 switch (op_) { | 1849 switch (op_) { |
| 1848 case Token::ADD: | 1850 case Token::ADD: |
| 1849 case Token::SUB: | 1851 case Token::SUB: |
| 1850 case Token::MUL: | 1852 case Token::MUL: |
| 1851 case Token::DIV: { | 1853 case Token::DIV: { |
| 1852 Label not_floats; | 1854 Label not_floats; |
| 1853 Label not_int32; | 1855 Label not_int32; |
| 1854 if (CpuFeatures::IsSupported(SSE2)) { | 1856 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 1855 CpuFeatures::Scope use_sse2(SSE2); | 1857 CpuFeatures::Scope use_sse2(SSE2); |
| 1856 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); | 1858 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); |
| 1857 FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); | 1859 FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); |
| 1858 switch (op_) { | 1860 switch (op_) { |
| 1859 case Token::ADD: __ addsd(xmm0, xmm1); break; | 1861 case Token::ADD: __ addsd(xmm0, xmm1); break; |
| 1860 case Token::SUB: __ subsd(xmm0, xmm1); break; | 1862 case Token::SUB: __ subsd(xmm0, xmm1); break; |
| 1861 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 1863 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| 1862 case Token::DIV: __ divsd(xmm0, xmm1); break; | 1864 case Token::DIV: __ divsd(xmm0, xmm1); break; |
| 1863 default: UNREACHABLE(); | 1865 default: UNREACHABLE(); |
| 1864 } | 1866 } |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1965 __ test(eax, Immediate(kSmiTagMask)); | 1967 __ test(eax, Immediate(kSmiTagMask)); |
| 1966 __ j(not_zero, &skip_allocation, not_taken); | 1968 __ j(not_zero, &skip_allocation, not_taken); |
| 1967 // Fall through! | 1969 // Fall through! |
| 1968 case NO_OVERWRITE: | 1970 case NO_OVERWRITE: |
| 1969 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | 1971 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
| 1970 __ bind(&skip_allocation); | 1972 __ bind(&skip_allocation); |
| 1971 break; | 1973 break; |
| 1972 default: UNREACHABLE(); | 1974 default: UNREACHABLE(); |
| 1973 } | 1975 } |
| 1974 // Store the result in the HeapNumber and return. | 1976 // Store the result in the HeapNumber and return. |
| 1975 if (CpuFeatures::IsSupported(SSE2)) { | 1977 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 1976 CpuFeatures::Scope use_sse2(SSE2); | 1978 CpuFeatures::Scope use_sse2(SSE2); |
| 1977 __ cvtsi2sd(xmm0, Operand(ebx)); | 1979 __ cvtsi2sd(xmm0, Operand(ebx)); |
| 1978 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 1980 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 1979 } else { | 1981 } else { |
| 1980 __ mov(Operand(esp, 1 * kPointerSize), ebx); | 1982 __ mov(Operand(esp, 1 * kPointerSize), ebx); |
| 1981 __ fild_s(Operand(esp, 1 * kPointerSize)); | 1983 __ fild_s(Operand(esp, 1 * kPointerSize)); |
| 1982 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 1984 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 1983 } | 1985 } |
| 1984 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. | 1986 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. |
| 1985 } | 1987 } |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2045 Label call_runtime; | 2047 Label call_runtime; |
| 2046 ASSERT(operands_type_ == TRBinaryOpIC::HEAP_NUMBER); | 2048 ASSERT(operands_type_ == TRBinaryOpIC::HEAP_NUMBER); |
| 2047 | 2049 |
| 2048 // Floating point case. | 2050 // Floating point case. |
| 2049 switch (op_) { | 2051 switch (op_) { |
| 2050 case Token::ADD: | 2052 case Token::ADD: |
| 2051 case Token::SUB: | 2053 case Token::SUB: |
| 2052 case Token::MUL: | 2054 case Token::MUL: |
| 2053 case Token::DIV: { | 2055 case Token::DIV: { |
| 2054 Label not_floats; | 2056 Label not_floats; |
| 2055 if (CpuFeatures::IsSupported(SSE2)) { | 2057 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 2056 CpuFeatures::Scope use_sse2(SSE2); | 2058 CpuFeatures::Scope use_sse2(SSE2); |
| 2057 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); | 2059 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); |
| 2058 | 2060 |
| 2059 switch (op_) { | 2061 switch (op_) { |
| 2060 case Token::ADD: __ addsd(xmm0, xmm1); break; | 2062 case Token::ADD: __ addsd(xmm0, xmm1); break; |
| 2061 case Token::SUB: __ subsd(xmm0, xmm1); break; | 2063 case Token::SUB: __ subsd(xmm0, xmm1); break; |
| 2062 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 2064 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| 2063 case Token::DIV: __ divsd(xmm0, xmm1); break; | 2065 case Token::DIV: __ divsd(xmm0, xmm1); break; |
| 2064 default: UNREACHABLE(); | 2066 default: UNREACHABLE(); |
| 2065 } | 2067 } |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2148 __ test(eax, Immediate(kSmiTagMask)); | 2150 __ test(eax, Immediate(kSmiTagMask)); |
| 2149 __ j(not_zero, &skip_allocation, not_taken); | 2151 __ j(not_zero, &skip_allocation, not_taken); |
| 2150 // Fall through! | 2152 // Fall through! |
| 2151 case NO_OVERWRITE: | 2153 case NO_OVERWRITE: |
| 2152 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | 2154 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
| 2153 __ bind(&skip_allocation); | 2155 __ bind(&skip_allocation); |
| 2154 break; | 2156 break; |
| 2155 default: UNREACHABLE(); | 2157 default: UNREACHABLE(); |
| 2156 } | 2158 } |
| 2157 // Store the result in the HeapNumber and return. | 2159 // Store the result in the HeapNumber and return. |
| 2158 if (CpuFeatures::IsSupported(SSE2)) { | 2160 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 2159 CpuFeatures::Scope use_sse2(SSE2); | 2161 CpuFeatures::Scope use_sse2(SSE2); |
| 2160 __ cvtsi2sd(xmm0, Operand(ebx)); | 2162 __ cvtsi2sd(xmm0, Operand(ebx)); |
| 2161 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 2163 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 2162 } else { | 2164 } else { |
| 2163 __ mov(Operand(esp, 1 * kPointerSize), ebx); | 2165 __ mov(Operand(esp, 1 * kPointerSize), ebx); |
| 2164 __ fild_s(Operand(esp, 1 * kPointerSize)); | 2166 __ fild_s(Operand(esp, 1 * kPointerSize)); |
| 2165 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 2167 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 2166 } | 2168 } |
| 2167 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. | 2169 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. |
| 2168 } | 2170 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2219 break; | 2221 break; |
| 2220 default: | 2222 default: |
| 2221 UNREACHABLE(); | 2223 UNREACHABLE(); |
| 2222 } | 2224 } |
| 2223 } | 2225 } |
| 2224 | 2226 |
| 2225 | 2227 |
| 2226 void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) { | 2228 void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) { |
| 2227 Label call_runtime; | 2229 Label call_runtime; |
| 2228 | 2230 |
| 2229 __ IncrementCounter(&Counters::generic_binary_stub_calls, 1); | 2231 __ IncrementCounter(COUNTERS->generic_binary_stub_calls(), 1); |
| 2230 | 2232 |
| 2231 switch (op_) { | 2233 switch (op_) { |
| 2232 case Token::ADD: | 2234 case Token::ADD: |
| 2233 case Token::SUB: | 2235 case Token::SUB: |
| 2234 case Token::MUL: | 2236 case Token::MUL: |
| 2235 case Token::DIV: | 2237 case Token::DIV: |
| 2236 break; | 2238 break; |
| 2237 case Token::MOD: | 2239 case Token::MOD: |
| 2238 case Token::BIT_OR: | 2240 case Token::BIT_OR: |
| 2239 case Token::BIT_AND: | 2241 case Token::BIT_AND: |
| 2240 case Token::BIT_XOR: | 2242 case Token::BIT_XOR: |
| 2241 case Token::SAR: | 2243 case Token::SAR: |
| 2242 case Token::SHL: | 2244 case Token::SHL: |
| 2243 case Token::SHR: | 2245 case Token::SHR: |
| 2244 GenerateRegisterArgsPush(masm); | 2246 GenerateRegisterArgsPush(masm); |
| 2245 break; | 2247 break; |
| 2246 default: | 2248 default: |
| 2247 UNREACHABLE(); | 2249 UNREACHABLE(); |
| 2248 } | 2250 } |
| 2249 | 2251 |
| 2250 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); | 2252 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); |
| 2251 | 2253 |
| 2252 // Floating point case. | 2254 // Floating point case. |
| 2253 switch (op_) { | 2255 switch (op_) { |
| 2254 case Token::ADD: | 2256 case Token::ADD: |
| 2255 case Token::SUB: | 2257 case Token::SUB: |
| 2256 case Token::MUL: | 2258 case Token::MUL: |
| 2257 case Token::DIV: { | 2259 case Token::DIV: { |
| 2258 Label not_floats; | 2260 Label not_floats; |
| 2259 if (CpuFeatures::IsSupported(SSE2)) { | 2261 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 2260 CpuFeatures::Scope use_sse2(SSE2); | 2262 CpuFeatures::Scope use_sse2(SSE2); |
| 2261 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); | 2263 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); |
| 2262 | 2264 |
| 2263 switch (op_) { | 2265 switch (op_) { |
| 2264 case Token::ADD: __ addsd(xmm0, xmm1); break; | 2266 case Token::ADD: __ addsd(xmm0, xmm1); break; |
| 2265 case Token::SUB: __ subsd(xmm0, xmm1); break; | 2267 case Token::SUB: __ subsd(xmm0, xmm1); break; |
| 2266 case Token::MUL: __ mulsd(xmm0, xmm1); break; | 2268 case Token::MUL: __ mulsd(xmm0, xmm1); break; |
| 2267 case Token::DIV: __ divsd(xmm0, xmm1); break; | 2269 case Token::DIV: __ divsd(xmm0, xmm1); break; |
| 2268 default: UNREACHABLE(); | 2270 default: UNREACHABLE(); |
| 2269 } | 2271 } |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2347 __ test(eax, Immediate(kSmiTagMask)); | 2349 __ test(eax, Immediate(kSmiTagMask)); |
| 2348 __ j(not_zero, &skip_allocation, not_taken); | 2350 __ j(not_zero, &skip_allocation, not_taken); |
| 2349 // Fall through! | 2351 // Fall through! |
| 2350 case NO_OVERWRITE: | 2352 case NO_OVERWRITE: |
| 2351 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); | 2353 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); |
| 2352 __ bind(&skip_allocation); | 2354 __ bind(&skip_allocation); |
| 2353 break; | 2355 break; |
| 2354 default: UNREACHABLE(); | 2356 default: UNREACHABLE(); |
| 2355 } | 2357 } |
| 2356 // Store the result in the HeapNumber and return. | 2358 // Store the result in the HeapNumber and return. |
| 2357 if (CpuFeatures::IsSupported(SSE2)) { | 2359 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 2358 CpuFeatures::Scope use_sse2(SSE2); | 2360 CpuFeatures::Scope use_sse2(SSE2); |
| 2359 __ cvtsi2sd(xmm0, Operand(ebx)); | 2361 __ cvtsi2sd(xmm0, Operand(ebx)); |
| 2360 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 2362 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 2361 } else { | 2363 } else { |
| 2362 __ mov(Operand(esp, 1 * kPointerSize), ebx); | 2364 __ mov(Operand(esp, 1 * kPointerSize), ebx); |
| 2363 __ fild_s(Operand(esp, 1 * kPointerSize)); | 2365 __ fild_s(Operand(esp, 1 * kPointerSize)); |
| 2364 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 2366 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 2365 } | 2367 } |
| 2366 __ ret(2 * kPointerSize); | 2368 __ ret(2 * kPointerSize); |
| 2367 } | 2369 } |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2535 __ sub(Operand(esp), Immediate(2 * kPointerSize)); | 2537 __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
| 2536 __ mov(Operand(esp, 0), eax); | 2538 __ mov(Operand(esp, 0), eax); |
| 2537 __ fild_s(Operand(esp, 0)); | 2539 __ fild_s(Operand(esp, 0)); |
| 2538 __ fst_d(Operand(esp, 0)); | 2540 __ fst_d(Operand(esp, 0)); |
| 2539 __ pop(edx); | 2541 __ pop(edx); |
| 2540 __ pop(ebx); | 2542 __ pop(ebx); |
| 2541 __ jmp(&loaded); | 2543 __ jmp(&loaded); |
| 2542 __ bind(&input_not_smi); | 2544 __ bind(&input_not_smi); |
| 2543 // Check if input is a HeapNumber. | 2545 // Check if input is a HeapNumber. |
| 2544 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 2546 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 2545 __ cmp(Operand(ebx), Immediate(Factory::heap_number_map())); | 2547 __ cmp(Operand(ebx), Immediate(FACTORY->heap_number_map())); |
| 2546 __ j(not_equal, &runtime_call); | 2548 __ j(not_equal, &runtime_call); |
| 2547 // Input is a HeapNumber. Push it on the FPU stack and load its | 2549 // Input is a HeapNumber. Push it on the FPU stack and load its |
| 2548 // low and high words into ebx, edx. | 2550 // low and high words into ebx, edx. |
| 2549 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 2551 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 2550 __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); | 2552 __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); |
| 2551 __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset)); | 2553 __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset)); |
| 2552 | 2554 |
| 2553 __ bind(&loaded); | 2555 __ bind(&loaded); |
| 2554 } else { // UNTAGGED. | 2556 } else { // UNTAGGED. |
| 2555 if (CpuFeatures::IsSupported(SSE4_1)) { | 2557 if (Isolate::Current()->cpu_features()->IsSupported(SSE4_1)) { |
| 2556 CpuFeatures::Scope sse4_scope(SSE4_1); | 2558 CpuFeatures::Scope sse4_scope(SSE4_1); |
| 2557 __ pextrd(Operand(edx), xmm1, 0x1); // copy xmm1[63..32] to edx. | 2559 __ pextrd(Operand(edx), xmm1, 0x1); // copy xmm1[63..32] to edx. |
| 2558 } else { | 2560 } else { |
| 2559 __ pshufd(xmm0, xmm1, 0x1); | 2561 __ pshufd(xmm0, xmm1, 0x1); |
| 2560 __ movd(Operand(edx), xmm0); | 2562 __ movd(Operand(edx), xmm0); |
| 2561 } | 2563 } |
| 2562 __ movd(Operand(ebx), xmm1); | 2564 __ movd(Operand(ebx), xmm1); |
| 2563 } | 2565 } |
| 2564 | 2566 |
| 2565 // ST[0] or xmm1 == double value | 2567 // ST[0] or xmm1 == double value |
| 2566 // ebx = low 32 bits of double value | 2568 // ebx = low 32 bits of double value |
| 2567 // edx = high 32 bits of double value | 2569 // edx = high 32 bits of double value |
| 2568 // Compute hash (the shifts are arithmetic): | 2570 // Compute hash (the shifts are arithmetic): |
| 2569 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); | 2571 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); |
| 2570 __ mov(ecx, ebx); | 2572 __ mov(ecx, ebx); |
| 2571 __ xor_(ecx, Operand(edx)); | 2573 __ xor_(ecx, Operand(edx)); |
| 2572 __ mov(eax, ecx); | 2574 __ mov(eax, ecx); |
| 2573 __ sar(eax, 16); | 2575 __ sar(eax, 16); |
| 2574 __ xor_(ecx, Operand(eax)); | 2576 __ xor_(ecx, Operand(eax)); |
| 2575 __ mov(eax, ecx); | 2577 __ mov(eax, ecx); |
| 2576 __ sar(eax, 8); | 2578 __ sar(eax, 8); |
| 2577 __ xor_(ecx, Operand(eax)); | 2579 __ xor_(ecx, Operand(eax)); |
| 2578 ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize)); | 2580 ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize)); |
| 2579 __ and_(Operand(ecx), Immediate(TranscendentalCache::kCacheSize - 1)); | 2581 __ and_(Operand(ecx), |
| 2582 Immediate(TranscendentalCache::SubCache::kCacheSize - 1)); |
| 2580 | 2583 |
| 2581 // ST[0] or xmm1 == double value. | 2584 // ST[0] or xmm1 == double value. |
| 2582 // ebx = low 32 bits of double value. | 2585 // ebx = low 32 bits of double value. |
| 2583 // edx = high 32 bits of double value. | 2586 // edx = high 32 bits of double value. |
| 2584 // ecx = TranscendentalCache::hash(double value). | 2587 // ecx = TranscendentalCache::hash(double value). |
| 2585 __ mov(eax, | 2588 __ mov(eax, |
| 2586 Immediate(ExternalReference::transcendental_cache_array_address())); | 2589 Immediate(ExternalReference::transcendental_cache_array_address())); |
| 2587 // Eax points to cache array. | 2590 // Eax points to cache array. |
| 2588 __ mov(eax, Operand(eax, type_ * sizeof(TranscendentalCache::caches_[0]))); | 2591 __ mov(eax, Operand(eax, type_ * sizeof( |
| 2592 Isolate::Current()->transcendental_cache()->caches_[0]))); |
| 2589 // Eax points to the cache for the type type_. | 2593 // Eax points to the cache for the type type_. |
| 2590 // If NULL, the cache hasn't been initialized yet, so go through runtime. | 2594 // If NULL, the cache hasn't been initialized yet, so go through runtime. |
| 2591 __ test(eax, Operand(eax)); | 2595 __ test(eax, Operand(eax)); |
| 2592 __ j(zero, &runtime_call_clear_stack); | 2596 __ j(zero, &runtime_call_clear_stack); |
| 2593 #ifdef DEBUG | 2597 #ifdef DEBUG |
| 2594 // Check that the layout of cache elements match expectations. | 2598 // Check that the layout of cache elements match expectations. |
| 2595 { TranscendentalCache::Element test_elem[2]; | 2599 { TranscendentalCache::SubCache::Element test_elem[2]; |
| 2596 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); | 2600 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); |
| 2597 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); | 2601 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); |
| 2598 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); | 2602 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); |
| 2599 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); | 2603 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); |
| 2600 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); | 2604 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); |
| 2601 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. | 2605 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. |
| 2602 CHECK_EQ(0, elem_in0 - elem_start); | 2606 CHECK_EQ(0, elem_in0 - elem_start); |
| 2603 CHECK_EQ(kIntSize, elem_in1 - elem_start); | 2607 CHECK_EQ(kIntSize, elem_in1 - elem_start); |
| 2604 CHECK_EQ(2 * kIntSize, elem_out - elem_start); | 2608 CHECK_EQ(2 * kIntSize, elem_out - elem_start); |
| 2605 } | 2609 } |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2794 // trashed registers. | 2798 // trashed registers. |
| 2795 void IntegerConvert(MacroAssembler* masm, | 2799 void IntegerConvert(MacroAssembler* masm, |
| 2796 Register source, | 2800 Register source, |
| 2797 TypeInfo type_info, | 2801 TypeInfo type_info, |
| 2798 bool use_sse3, | 2802 bool use_sse3, |
| 2799 Label* conversion_failure) { | 2803 Label* conversion_failure) { |
| 2800 ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); | 2804 ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); |
| 2801 Label done, right_exponent, normal_exponent; | 2805 Label done, right_exponent, normal_exponent; |
| 2802 Register scratch = ebx; | 2806 Register scratch = ebx; |
| 2803 Register scratch2 = edi; | 2807 Register scratch2 = edi; |
| 2804 if (type_info.IsInteger32() && CpuFeatures::IsEnabled(SSE2)) { | 2808 if (type_info.IsInteger32() && |
| 2809 Isolate::Current()->cpu_features()->IsEnabled(SSE2)) { |
| 2805 CpuFeatures::Scope scope(SSE2); | 2810 CpuFeatures::Scope scope(SSE2); |
| 2806 __ cvttsd2si(ecx, FieldOperand(source, HeapNumber::kValueOffset)); | 2811 __ cvttsd2si(ecx, FieldOperand(source, HeapNumber::kValueOffset)); |
| 2807 return; | 2812 return; |
| 2808 } | 2813 } |
| 2809 if (!type_info.IsInteger32() || !use_sse3) { | 2814 if (!type_info.IsInteger32() || !use_sse3) { |
| 2810 // Get exponent word. | 2815 // Get exponent word. |
| 2811 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); | 2816 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); |
| 2812 // Get exponent alone in scratch2. | 2817 // Get exponent alone in scratch2. |
| 2813 __ mov(scratch2, scratch); | 2818 __ mov(scratch2, scratch); |
| 2814 __ and_(scratch2, HeapNumber::kExponentMask); | 2819 __ and_(scratch2, HeapNumber::kExponentMask); |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2997 | 3002 |
| 2998 // Test if arg1 is a Smi. | 3003 // Test if arg1 is a Smi. |
| 2999 __ test(edx, Immediate(kSmiTagMask)); | 3004 __ test(edx, Immediate(kSmiTagMask)); |
| 3000 __ j(not_zero, &arg1_is_object); | 3005 __ j(not_zero, &arg1_is_object); |
| 3001 | 3006 |
| 3002 __ SmiUntag(edx); | 3007 __ SmiUntag(edx); |
| 3003 __ jmp(&load_arg2); | 3008 __ jmp(&load_arg2); |
| 3004 | 3009 |
| 3005 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 3010 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
| 3006 __ bind(&check_undefined_arg1); | 3011 __ bind(&check_undefined_arg1); |
| 3007 __ cmp(edx, Factory::undefined_value()); | 3012 __ cmp(edx, FACTORY->undefined_value()); |
| 3008 __ j(not_equal, conversion_failure); | 3013 __ j(not_equal, conversion_failure); |
| 3009 __ mov(edx, Immediate(0)); | 3014 __ mov(edx, Immediate(0)); |
| 3010 __ jmp(&load_arg2); | 3015 __ jmp(&load_arg2); |
| 3011 | 3016 |
| 3012 __ bind(&arg1_is_object); | 3017 __ bind(&arg1_is_object); |
| 3013 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); | 3018 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3014 __ cmp(ebx, Factory::heap_number_map()); | 3019 __ cmp(ebx, FACTORY->heap_number_map()); |
| 3015 __ j(not_equal, &check_undefined_arg1); | 3020 __ j(not_equal, &check_undefined_arg1); |
| 3016 | 3021 |
| 3017 // Get the untagged integer version of the edx heap number in ecx. | 3022 // Get the untagged integer version of the edx heap number in ecx. |
| 3018 IntegerConvert(masm, | 3023 IntegerConvert(masm, |
| 3019 edx, | 3024 edx, |
| 3020 TypeInfo::Unknown(), | 3025 TypeInfo::Unknown(), |
| 3021 use_sse3, | 3026 use_sse3, |
| 3022 conversion_failure); | 3027 conversion_failure); |
| 3023 __ mov(edx, ecx); | 3028 __ mov(edx, ecx); |
| 3024 | 3029 |
| 3025 // Here edx has the untagged integer, eax has a Smi or a heap number. | 3030 // Here edx has the untagged integer, eax has a Smi or a heap number. |
| 3026 __ bind(&load_arg2); | 3031 __ bind(&load_arg2); |
| 3027 | 3032 |
| 3028 // Test if arg2 is a Smi. | 3033 // Test if arg2 is a Smi. |
| 3029 __ test(eax, Immediate(kSmiTagMask)); | 3034 __ test(eax, Immediate(kSmiTagMask)); |
| 3030 __ j(not_zero, &arg2_is_object); | 3035 __ j(not_zero, &arg2_is_object); |
| 3031 | 3036 |
| 3032 __ SmiUntag(eax); | 3037 __ SmiUntag(eax); |
| 3033 __ mov(ecx, eax); | 3038 __ mov(ecx, eax); |
| 3034 __ jmp(&done); | 3039 __ jmp(&done); |
| 3035 | 3040 |
| 3036 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). | 3041 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). |
| 3037 __ bind(&check_undefined_arg2); | 3042 __ bind(&check_undefined_arg2); |
| 3038 __ cmp(eax, Factory::undefined_value()); | 3043 __ cmp(eax, FACTORY->undefined_value()); |
| 3039 __ j(not_equal, conversion_failure); | 3044 __ j(not_equal, conversion_failure); |
| 3040 __ mov(ecx, Immediate(0)); | 3045 __ mov(ecx, Immediate(0)); |
| 3041 __ jmp(&done); | 3046 __ jmp(&done); |
| 3042 | 3047 |
| 3043 __ bind(&arg2_is_object); | 3048 __ bind(&arg2_is_object); |
| 3044 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 3049 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3045 __ cmp(ebx, Factory::heap_number_map()); | 3050 __ cmp(ebx, FACTORY->heap_number_map()); |
| 3046 __ j(not_equal, &check_undefined_arg2); | 3051 __ j(not_equal, &check_undefined_arg2); |
| 3047 | 3052 |
| 3048 // Get the untagged integer version of the eax heap number in ecx. | 3053 // Get the untagged integer version of the eax heap number in ecx. |
| 3049 IntegerConvert(masm, | 3054 IntegerConvert(masm, |
| 3050 eax, | 3055 eax, |
| 3051 TypeInfo::Unknown(), | 3056 TypeInfo::Unknown(), |
| 3052 use_sse3, | 3057 use_sse3, |
| 3053 conversion_failure); | 3058 conversion_failure); |
| 3054 __ bind(&done); | 3059 __ bind(&done); |
| 3055 __ mov(eax, edx); | 3060 __ mov(eax, edx); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3122 __ bind(&done); | 3127 __ bind(&done); |
| 3123 } | 3128 } |
| 3124 | 3129 |
| 3125 | 3130 |
| 3126 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, | 3131 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, |
| 3127 Label* not_numbers) { | 3132 Label* not_numbers) { |
| 3128 NearLabel load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; | 3133 NearLabel load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; |
| 3129 // Load operand in edx into xmm0, or branch to not_numbers. | 3134 // Load operand in edx into xmm0, or branch to not_numbers. |
| 3130 __ test(edx, Immediate(kSmiTagMask)); | 3135 __ test(edx, Immediate(kSmiTagMask)); |
| 3131 __ j(zero, &load_smi_edx, not_taken); // Argument in edx is a smi. | 3136 __ j(zero, &load_smi_edx, not_taken); // Argument in edx is a smi. |
| 3132 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), Factory::heap_number_map()); | 3137 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), FACTORY->heap_number_map()); |
| 3133 __ j(not_equal, not_numbers); // Argument in edx is not a number. | 3138 __ j(not_equal, not_numbers); // Argument in edx is not a number. |
| 3134 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 3139 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |
| 3135 __ bind(&load_eax); | 3140 __ bind(&load_eax); |
| 3136 // Load operand in eax into xmm1, or branch to not_numbers. | 3141 // Load operand in eax into xmm1, or branch to not_numbers. |
| 3137 __ test(eax, Immediate(kSmiTagMask)); | 3142 __ test(eax, Immediate(kSmiTagMask)); |
| 3138 __ j(zero, &load_smi_eax, not_taken); // Argument in eax is a smi. | 3143 __ j(zero, &load_smi_eax, not_taken); // Argument in eax is a smi. |
| 3139 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::heap_number_map()); | 3144 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), FACTORY->heap_number_map()); |
| 3140 __ j(equal, &load_float_eax); | 3145 __ j(equal, &load_float_eax); |
| 3141 __ jmp(not_numbers); // Argument in eax is not a number. | 3146 __ jmp(not_numbers); // Argument in eax is not a number. |
| 3142 __ bind(&load_smi_edx); | 3147 __ bind(&load_smi_edx); |
| 3143 __ SmiUntag(edx); // Untag smi before converting to float. | 3148 __ SmiUntag(edx); // Untag smi before converting to float. |
| 3144 __ cvtsi2sd(xmm0, Operand(edx)); | 3149 __ cvtsi2sd(xmm0, Operand(edx)); |
| 3145 __ SmiTag(edx); // Retag smi for heap number overwriting test. | 3150 __ SmiTag(edx); // Retag smi for heap number overwriting test. |
| 3146 __ jmp(&load_eax); | 3151 __ jmp(&load_eax); |
| 3147 __ bind(&load_smi_eax); | 3152 __ bind(&load_smi_eax); |
| 3148 __ SmiUntag(eax); // Untag smi before converting to float. | 3153 __ SmiUntag(eax); // Untag smi before converting to float. |
| 3149 __ cvtsi2sd(xmm1, Operand(eax)); | 3154 __ cvtsi2sd(xmm1, Operand(eax)); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3247 | 3252 |
| 3248 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, | 3253 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, |
| 3249 Label* non_float, | 3254 Label* non_float, |
| 3250 Register scratch) { | 3255 Register scratch) { |
| 3251 NearLabel test_other, done; | 3256 NearLabel test_other, done; |
| 3252 // Test if both operands are floats or smi -> scratch=k_is_float; | 3257 // Test if both operands are floats or smi -> scratch=k_is_float; |
| 3253 // Otherwise scratch = k_not_float. | 3258 // Otherwise scratch = k_not_float. |
| 3254 __ test(edx, Immediate(kSmiTagMask)); | 3259 __ test(edx, Immediate(kSmiTagMask)); |
| 3255 __ j(zero, &test_other, not_taken); // argument in edx is OK | 3260 __ j(zero, &test_other, not_taken); // argument in edx is OK |
| 3256 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); | 3261 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3257 __ cmp(scratch, Factory::heap_number_map()); | 3262 __ cmp(scratch, FACTORY->heap_number_map()); |
| 3258 __ j(not_equal, non_float); // argument in edx is not a number -> NaN | 3263 __ j(not_equal, non_float); // argument in edx is not a number -> NaN |
| 3259 | 3264 |
| 3260 __ bind(&test_other); | 3265 __ bind(&test_other); |
| 3261 __ test(eax, Immediate(kSmiTagMask)); | 3266 __ test(eax, Immediate(kSmiTagMask)); |
| 3262 __ j(zero, &done); // argument in eax is OK | 3267 __ j(zero, &done); // argument in eax is OK |
| 3263 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); | 3268 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3264 __ cmp(scratch, Factory::heap_number_map()); | 3269 __ cmp(scratch, FACTORY->heap_number_map()); |
| 3265 __ j(not_equal, non_float); // argument in eax is not a number -> NaN | 3270 __ j(not_equal, non_float); // argument in eax is not a number -> NaN |
| 3266 | 3271 |
| 3267 // Fall-through: Both operands are numbers. | 3272 // Fall-through: Both operands are numbers. |
| 3268 __ bind(&done); | 3273 __ bind(&done); |
| 3269 } | 3274 } |
| 3270 | 3275 |
| 3271 | 3276 |
| 3272 void FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm, | 3277 void FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm, |
| 3273 Label* non_int32) { | 3278 Label* non_int32) { |
| 3274 return; | 3279 return; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 3300 __ j(overflow, &undo, not_taken); | 3305 __ j(overflow, &undo, not_taken); |
| 3301 __ StubReturn(1); | 3306 __ StubReturn(1); |
| 3302 | 3307 |
| 3303 // Try floating point case. | 3308 // Try floating point case. |
| 3304 __ bind(&try_float); | 3309 __ bind(&try_float); |
| 3305 } else if (FLAG_debug_code) { | 3310 } else if (FLAG_debug_code) { |
| 3306 __ AbortIfSmi(eax); | 3311 __ AbortIfSmi(eax); |
| 3307 } | 3312 } |
| 3308 | 3313 |
| 3309 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 3314 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3310 __ cmp(edx, Factory::heap_number_map()); | 3315 __ cmp(edx, FACTORY->heap_number_map()); |
| 3311 __ j(not_equal, &slow); | 3316 __ j(not_equal, &slow); |
| 3312 if (overwrite_ == UNARY_OVERWRITE) { | 3317 if (overwrite_ == UNARY_OVERWRITE) { |
| 3313 __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); | 3318 __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); |
| 3314 __ xor_(edx, HeapNumber::kSignMask); // Flip sign. | 3319 __ xor_(edx, HeapNumber::kSignMask); // Flip sign. |
| 3315 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), edx); | 3320 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), edx); |
| 3316 } else { | 3321 } else { |
| 3317 __ mov(edx, Operand(eax)); | 3322 __ mov(edx, Operand(eax)); |
| 3318 // edx: operand | 3323 // edx: operand |
| 3319 __ AllocateHeapNumber(eax, ebx, ecx, &undo); | 3324 __ AllocateHeapNumber(eax, ebx, ecx, &undo); |
| 3320 // eax: allocated 'empty' number | 3325 // eax: allocated 'empty' number |
| (...skipping 11 matching lines...) Expand all Loading... |
| 3332 __ not_(eax); | 3337 __ not_(eax); |
| 3333 __ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag. | 3338 __ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag. |
| 3334 __ ret(0); | 3339 __ ret(0); |
| 3335 __ bind(&non_smi); | 3340 __ bind(&non_smi); |
| 3336 } else if (FLAG_debug_code) { | 3341 } else if (FLAG_debug_code) { |
| 3337 __ AbortIfSmi(eax); | 3342 __ AbortIfSmi(eax); |
| 3338 } | 3343 } |
| 3339 | 3344 |
| 3340 // Check if the operand is a heap number. | 3345 // Check if the operand is a heap number. |
| 3341 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); | 3346 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3342 __ cmp(edx, Factory::heap_number_map()); | 3347 __ cmp(edx, FACTORY->heap_number_map()); |
| 3343 __ j(not_equal, &slow, not_taken); | 3348 __ j(not_equal, &slow, not_taken); |
| 3344 | 3349 |
| 3345 // Convert the heap number in eax to an untagged integer in ecx. | 3350 // Convert the heap number in eax to an untagged integer in ecx. |
| 3346 IntegerConvert(masm, | 3351 IntegerConvert(masm, |
| 3347 eax, | 3352 eax, |
| 3348 TypeInfo::Unknown(), | 3353 TypeInfo::Unknown(), |
| 3349 CpuFeatures::IsSupported(SSE3), | 3354 Isolate::Current()->cpu_features()->IsSupported(SSE3), |
| 3350 &slow); | 3355 &slow); |
| 3351 | 3356 |
| 3352 // Do the bitwise operation and check if the result fits in a smi. | 3357 // Do the bitwise operation and check if the result fits in a smi. |
| 3353 NearLabel try_float; | 3358 NearLabel try_float; |
| 3354 __ not_(ecx); | 3359 __ not_(ecx); |
| 3355 __ cmp(ecx, 0xc0000000); | 3360 __ cmp(ecx, 0xc0000000); |
| 3356 __ j(sign, &try_float, not_taken); | 3361 __ j(sign, &try_float, not_taken); |
| 3357 | 3362 |
| 3358 // Tag the result as a smi and we're done. | 3363 // Tag the result as a smi and we're done. |
| 3359 STATIC_ASSERT(kSmiTagSize == 1); | 3364 STATIC_ASSERT(kSmiTagSize == 1); |
| 3360 __ lea(eax, Operand(ecx, times_2, kSmiTag)); | 3365 __ lea(eax, Operand(ecx, times_2, kSmiTag)); |
| 3361 __ jmp(&done); | 3366 __ jmp(&done); |
| 3362 | 3367 |
| 3363 // Try to store the result in a heap number. | 3368 // Try to store the result in a heap number. |
| 3364 __ bind(&try_float); | 3369 __ bind(&try_float); |
| 3365 if (overwrite_ == UNARY_NO_OVERWRITE) { | 3370 if (overwrite_ == UNARY_NO_OVERWRITE) { |
| 3366 // Allocate a fresh heap number, but don't overwrite eax until | 3371 // Allocate a fresh heap number, but don't overwrite eax until |
| 3367 // we're sure we can do it without going through the slow case | 3372 // we're sure we can do it without going through the slow case |
| 3368 // that needs the value in eax. | 3373 // that needs the value in eax. |
| 3369 __ AllocateHeapNumber(ebx, edx, edi, &slow); | 3374 __ AllocateHeapNumber(ebx, edx, edi, &slow); |
| 3370 __ mov(eax, Operand(ebx)); | 3375 __ mov(eax, Operand(ebx)); |
| 3371 } | 3376 } |
| 3372 if (CpuFeatures::IsSupported(SSE2)) { | 3377 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 3373 CpuFeatures::Scope use_sse2(SSE2); | 3378 CpuFeatures::Scope use_sse2(SSE2); |
| 3374 __ cvtsi2sd(xmm0, Operand(ecx)); | 3379 __ cvtsi2sd(xmm0, Operand(ecx)); |
| 3375 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); | 3380 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); |
| 3376 } else { | 3381 } else { |
| 3377 __ push(ecx); | 3382 __ push(ecx); |
| 3378 __ fild_s(Operand(esp, 0)); | 3383 __ fild_s(Operand(esp, 0)); |
| 3379 __ pop(ecx); | 3384 __ pop(ecx); |
| 3380 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 3385 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3381 } | 3386 } |
| 3382 } else { | 3387 } else { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3435 __ j(not_zero, &base_nonsmi); | 3440 __ j(not_zero, &base_nonsmi); |
| 3436 | 3441 |
| 3437 // Optimized version when both exponent and base are smis. | 3442 // Optimized version when both exponent and base are smis. |
| 3438 Label powi; | 3443 Label powi; |
| 3439 __ SmiUntag(edx); | 3444 __ SmiUntag(edx); |
| 3440 __ cvtsi2sd(xmm0, Operand(edx)); | 3445 __ cvtsi2sd(xmm0, Operand(edx)); |
| 3441 __ jmp(&powi); | 3446 __ jmp(&powi); |
| 3442 // exponent is smi and base is a heapnumber. | 3447 // exponent is smi and base is a heapnumber. |
| 3443 __ bind(&base_nonsmi); | 3448 __ bind(&base_nonsmi); |
| 3444 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 3449 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 3445 Factory::heap_number_map()); | 3450 FACTORY->heap_number_map()); |
| 3446 __ j(not_equal, &call_runtime); | 3451 __ j(not_equal, &call_runtime); |
| 3447 | 3452 |
| 3448 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 3453 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |
| 3449 | 3454 |
| 3450 // Optimized version of pow if exponent is a smi. | 3455 // Optimized version of pow if exponent is a smi. |
| 3451 // xmm0 contains the base. | 3456 // xmm0 contains the base. |
| 3452 __ bind(&powi); | 3457 __ bind(&powi); |
| 3453 __ SmiUntag(eax); | 3458 __ SmiUntag(eax); |
| 3454 | 3459 |
| 3455 // Save exponent in base as we need to check if exponent is negative later. | 3460 // Save exponent in base as we need to check if exponent is negative later. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3487 __ ucomisd(xmm0, xmm1); | 3492 __ ucomisd(xmm0, xmm1); |
| 3488 __ j(equal, &call_runtime); | 3493 __ j(equal, &call_runtime); |
| 3489 __ divsd(xmm3, xmm1); | 3494 __ divsd(xmm3, xmm1); |
| 3490 __ movsd(xmm1, xmm3); | 3495 __ movsd(xmm1, xmm3); |
| 3491 __ jmp(&allocate_return); | 3496 __ jmp(&allocate_return); |
| 3492 | 3497 |
| 3493 // exponent (or both) is a heapnumber - no matter what we should now work | 3498 // exponent (or both) is a heapnumber - no matter what we should now work |
| 3494 // on doubles. | 3499 // on doubles. |
| 3495 __ bind(&exponent_nonsmi); | 3500 __ bind(&exponent_nonsmi); |
| 3496 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 3501 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 3497 Factory::heap_number_map()); | 3502 FACTORY->heap_number_map()); |
| 3498 __ j(not_equal, &call_runtime); | 3503 __ j(not_equal, &call_runtime); |
| 3499 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 3504 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3500 // Test if exponent is nan. | 3505 // Test if exponent is nan. |
| 3501 __ ucomisd(xmm1, xmm1); | 3506 __ ucomisd(xmm1, xmm1); |
| 3502 __ j(parity_even, &call_runtime); | 3507 __ j(parity_even, &call_runtime); |
| 3503 | 3508 |
| 3504 NearLabel base_not_smi; | 3509 NearLabel base_not_smi; |
| 3505 NearLabel handle_special_cases; | 3510 NearLabel handle_special_cases; |
| 3506 __ test(edx, Immediate(kSmiTagMask)); | 3511 __ test(edx, Immediate(kSmiTagMask)); |
| 3507 __ j(not_zero, &base_not_smi); | 3512 __ j(not_zero, &base_not_smi); |
| 3508 __ SmiUntag(edx); | 3513 __ SmiUntag(edx); |
| 3509 __ cvtsi2sd(xmm0, Operand(edx)); | 3514 __ cvtsi2sd(xmm0, Operand(edx)); |
| 3510 __ jmp(&handle_special_cases); | 3515 __ jmp(&handle_special_cases); |
| 3511 | 3516 |
| 3512 __ bind(&base_not_smi); | 3517 __ bind(&base_not_smi); |
| 3513 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 3518 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 3514 Factory::heap_number_map()); | 3519 FACTORY->heap_number_map()); |
| 3515 __ j(not_equal, &call_runtime); | 3520 __ j(not_equal, &call_runtime); |
| 3516 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); | 3521 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); |
| 3517 __ and_(ecx, HeapNumber::kExponentMask); | 3522 __ and_(ecx, HeapNumber::kExponentMask); |
| 3518 __ cmp(Operand(ecx), Immediate(HeapNumber::kExponentMask)); | 3523 __ cmp(Operand(ecx), Immediate(HeapNumber::kExponentMask)); |
| 3519 // base is NaN or +/-Infinity | 3524 // base is NaN or +/-Infinity |
| 3520 __ j(greater_equal, &call_runtime); | 3525 __ j(greater_equal, &call_runtime); |
| 3521 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 3526 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |
| 3522 | 3527 |
| 3523 // base is in xmm0 and exponent is in xmm1. | 3528 // base is in xmm0 and exponent is in xmm1. |
| 3524 __ bind(&handle_special_cases); | 3529 __ bind(&handle_special_cases); |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3702 __ j(zero, &done); | 3707 __ j(zero, &done); |
| 3703 | 3708 |
| 3704 // Get the parameters pointer from the stack. | 3709 // Get the parameters pointer from the stack. |
| 3705 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 3710 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 3706 | 3711 |
| 3707 // Setup the elements pointer in the allocated arguments object and | 3712 // Setup the elements pointer in the allocated arguments object and |
| 3708 // initialize the header in the elements fixed array. | 3713 // initialize the header in the elements fixed array. |
| 3709 __ lea(edi, Operand(eax, GetArgumentsObjectSize())); | 3714 __ lea(edi, Operand(eax, GetArgumentsObjectSize())); |
| 3710 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); | 3715 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); |
| 3711 __ mov(FieldOperand(edi, FixedArray::kMapOffset), | 3716 __ mov(FieldOperand(edi, FixedArray::kMapOffset), |
| 3712 Immediate(Factory::fixed_array_map())); | 3717 Immediate(FACTORY->fixed_array_map())); |
| 3713 | 3718 |
| 3714 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); | 3719 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); |
| 3715 // Untag the length for the loop below. | 3720 // Untag the length for the loop below. |
| 3716 __ SmiUntag(ecx); | 3721 __ SmiUntag(ecx); |
| 3717 | 3722 |
| 3718 // Copy the fixed array slots. | 3723 // Copy the fixed array slots. |
| 3719 NearLabel loop; | 3724 NearLabel loop; |
| 3720 __ bind(&loop); | 3725 __ bind(&loop); |
| 3721 __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver. | 3726 __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver. |
| 3722 __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx); | 3727 __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3830 // edx: Number of capture registers | 3835 // edx: Number of capture registers |
| 3831 // Check that the fourth object is a JSArray object. | 3836 // Check that the fourth object is a JSArray object. |
| 3832 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); | 3837 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); |
| 3833 __ test(eax, Immediate(kSmiTagMask)); | 3838 __ test(eax, Immediate(kSmiTagMask)); |
| 3834 __ j(zero, &runtime); | 3839 __ j(zero, &runtime); |
| 3835 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); | 3840 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); |
| 3836 __ j(not_equal, &runtime); | 3841 __ j(not_equal, &runtime); |
| 3837 // Check that the JSArray is in fast case. | 3842 // Check that the JSArray is in fast case. |
| 3838 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); | 3843 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); |
| 3839 __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); | 3844 __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); |
| 3840 __ cmp(eax, Factory::fixed_array_map()); | 3845 __ cmp(eax, FACTORY->fixed_array_map()); |
| 3841 __ j(not_equal, &runtime); | 3846 __ j(not_equal, &runtime); |
| 3842 // Check that the last match info has space for the capture registers and the | 3847 // Check that the last match info has space for the capture registers and the |
| 3843 // additional information. | 3848 // additional information. |
| 3844 __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); | 3849 __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); |
| 3845 __ SmiUntag(eax); | 3850 __ SmiUntag(eax); |
| 3846 __ add(Operand(edx), Immediate(RegExpImpl::kLastMatchOverhead)); | 3851 __ add(Operand(edx), Immediate(RegExpImpl::kLastMatchOverhead)); |
| 3847 __ cmp(edx, Operand(eax)); | 3852 __ cmp(edx, Operand(eax)); |
| 3848 __ j(greater, &runtime); | 3853 __ j(greater, &runtime); |
| 3849 | 3854 |
| 3850 // ecx: RegExp data (FixedArray) | 3855 // ecx: RegExp data (FixedArray) |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3868 // string. In that case the subject string is just the first part of the cons | 3873 // string. In that case the subject string is just the first part of the cons |
| 3869 // string. Also in this case the first part of the cons string is known to be | 3874 // string. Also in this case the first part of the cons string is known to be |
| 3870 // a sequential string or an external string. | 3875 // a sequential string or an external string. |
| 3871 STATIC_ASSERT(kExternalStringTag != 0); | 3876 STATIC_ASSERT(kExternalStringTag != 0); |
| 3872 STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); | 3877 STATIC_ASSERT((kConsStringTag & kExternalStringTag) == 0); |
| 3873 __ test(Operand(ebx), | 3878 __ test(Operand(ebx), |
| 3874 Immediate(kIsNotStringMask | kExternalStringTag)); | 3879 Immediate(kIsNotStringMask | kExternalStringTag)); |
| 3875 __ j(not_zero, &runtime); | 3880 __ j(not_zero, &runtime); |
| 3876 // String is a cons string. | 3881 // String is a cons string. |
| 3877 __ mov(edx, FieldOperand(eax, ConsString::kSecondOffset)); | 3882 __ mov(edx, FieldOperand(eax, ConsString::kSecondOffset)); |
| 3878 __ cmp(Operand(edx), Factory::empty_string()); | 3883 __ cmp(Operand(edx), FACTORY->empty_string()); |
| 3879 __ j(not_equal, &runtime); | 3884 __ j(not_equal, &runtime); |
| 3880 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); | 3885 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); |
| 3881 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 3886 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 3882 // String is a cons string with empty second part. | 3887 // String is a cons string with empty second part. |
| 3883 // eax: first part of cons string. | 3888 // eax: first part of cons string. |
| 3884 // ebx: map of first part of cons string. | 3889 // ebx: map of first part of cons string. |
| 3885 // Is first part a flat two byte string? | 3890 // Is first part a flat two byte string? |
| 3886 __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), | 3891 __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), |
| 3887 kStringRepresentationMask | kStringEncodingMask); | 3892 kStringRepresentationMask | kStringEncodingMask); |
| 3888 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); | 3893 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 3918 // Load used arguments before starting to push arguments for call to native | 3923 // Load used arguments before starting to push arguments for call to native |
| 3919 // RegExp code to avoid handling changing stack height. | 3924 // RegExp code to avoid handling changing stack height. |
| 3920 __ mov(ebx, Operand(esp, kPreviousIndexOffset)); | 3925 __ mov(ebx, Operand(esp, kPreviousIndexOffset)); |
| 3921 __ SmiUntag(ebx); // Previous index from smi. | 3926 __ SmiUntag(ebx); // Previous index from smi. |
| 3922 | 3927 |
| 3923 // eax: subject string | 3928 // eax: subject string |
| 3924 // ebx: previous index | 3929 // ebx: previous index |
| 3925 // edx: code | 3930 // edx: code |
| 3926 // edi: encoding of subject string (1 if ascii 0 if two_byte); | 3931 // edi: encoding of subject string (1 if ascii 0 if two_byte); |
| 3927 // All checks done. Now push arguments for native regexp code. | 3932 // All checks done. Now push arguments for native regexp code. |
| 3928 __ IncrementCounter(&Counters::regexp_entry_native, 1); | 3933 __ IncrementCounter(COUNTERS->regexp_entry_native(), 1); |
| 3929 | 3934 |
| 3930 static const int kRegExpExecuteArguments = 7; | 3935 // Isolates: note we add an additional parameter here (isolate pointer). |
| 3936 static const int kRegExpExecuteArguments = 8; |
| 3931 __ EnterApiExitFrame(kRegExpExecuteArguments); | 3937 __ EnterApiExitFrame(kRegExpExecuteArguments); |
| 3932 | 3938 |
| 3939 // Argument 8: Pass current isolate address. |
| 3940 __ mov(Operand(esp, 7 * kPointerSize), |
| 3941 Immediate(ExternalReference::isolate_address())); |
| 3942 |
| 3933 // Argument 7: Indicate that this is a direct call from JavaScript. | 3943 // Argument 7: Indicate that this is a direct call from JavaScript. |
| 3934 __ mov(Operand(esp, 6 * kPointerSize), Immediate(1)); | 3944 __ mov(Operand(esp, 6 * kPointerSize), Immediate(1)); |
| 3935 | 3945 |
| 3936 // Argument 6: Start (high end) of backtracking stack memory area. | 3946 // Argument 6: Start (high end) of backtracking stack memory area. |
| 3937 __ mov(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_address)); | 3947 __ mov(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_address)); |
| 3938 __ add(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); | 3948 __ add(ecx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); |
| 3939 __ mov(Operand(esp, 5 * kPointerSize), ecx); | 3949 __ mov(Operand(esp, 5 * kPointerSize), ecx); |
| 3940 | 3950 |
| 3941 // Argument 5: static offsets vector buffer. | 3951 // Argument 5: static offsets vector buffer. |
| 3942 __ mov(Operand(esp, 4 * kPointerSize), | 3952 __ mov(Operand(esp, 4 * kPointerSize), |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3985 Label failure; | 3995 Label failure; |
| 3986 __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); | 3996 __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); |
| 3987 __ j(equal, &failure, taken); | 3997 __ j(equal, &failure, taken); |
| 3988 __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); | 3998 __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); |
| 3989 // If not exception it can only be retry. Handle that in the runtime system. | 3999 // If not exception it can only be retry. Handle that in the runtime system. |
| 3990 __ j(not_equal, &runtime); | 4000 __ j(not_equal, &runtime); |
| 3991 // Result must now be exception. If there is no pending exception already a | 4001 // Result must now be exception. If there is no pending exception already a |
| 3992 // stack overflow (on the backtrack stack) was detected in RegExp code but | 4002 // stack overflow (on the backtrack stack) was detected in RegExp code but |
| 3993 // haven't created the exception yet. Handle that in the runtime system. | 4003 // haven't created the exception yet. Handle that in the runtime system. |
| 3994 // TODO(592): Rerunning the RegExp to get the stack overflow exception. | 4004 // TODO(592): Rerunning the RegExp to get the stack overflow exception. |
| 3995 ExternalReference pending_exception(Top::k_pending_exception_address); | 4005 ExternalReference pending_exception(Isolate::k_pending_exception_address); |
| 3996 __ mov(edx, | 4006 __ mov(edx, |
| 3997 Operand::StaticVariable(ExternalReference::the_hole_value_location())); | 4007 Operand::StaticVariable(ExternalReference::the_hole_value_location())); |
| 3998 __ mov(eax, Operand::StaticVariable(pending_exception)); | 4008 __ mov(eax, Operand::StaticVariable(pending_exception)); |
| 3999 __ cmp(edx, Operand(eax)); | 4009 __ cmp(edx, Operand(eax)); |
| 4000 __ j(equal, &runtime); | 4010 __ j(equal, &runtime); |
| 4001 // For exception, throw the exception again. | 4011 // For exception, throw the exception again. |
| 4002 | 4012 |
| 4003 // Clear the pending exception variable. | 4013 // Clear the pending exception variable. |
| 4004 __ mov(Operand::StaticVariable(pending_exception), edx); | 4014 __ mov(Operand::StaticVariable(pending_exception), edx); |
| 4005 | 4015 |
| 4006 // Special handling of termination exceptions which are uncatchable | 4016 // Special handling of termination exceptions which are uncatchable |
| 4007 // by javascript code. | 4017 // by javascript code. |
| 4008 __ cmp(eax, Factory::termination_exception()); | 4018 __ cmp(eax, FACTORY->termination_exception()); |
| 4009 Label throw_termination_exception; | 4019 Label throw_termination_exception; |
| 4010 __ j(equal, &throw_termination_exception); | 4020 __ j(equal, &throw_termination_exception); |
| 4011 | 4021 |
| 4012 // Handle normal exception by following handler chain. | 4022 // Handle normal exception by following handler chain. |
| 4013 __ Throw(eax); | 4023 __ Throw(eax); |
| 4014 | 4024 |
| 4015 __ bind(&throw_termination_exception); | 4025 __ bind(&throw_termination_exception); |
| 4016 __ ThrowUncatchable(TERMINATION, eax); | 4026 __ ThrowUncatchable(TERMINATION, eax); |
| 4017 | 4027 |
| 4018 __ bind(&failure); | 4028 __ bind(&failure); |
| 4019 // For failure to match, return null. | 4029 // For failure to match, return null. |
| 4020 __ mov(Operand(eax), Factory::null_value()); | 4030 __ mov(Operand(eax), FACTORY->null_value()); |
| 4021 __ ret(4 * kPointerSize); | 4031 __ ret(4 * kPointerSize); |
| 4022 | 4032 |
| 4023 // Load RegExp data. | 4033 // Load RegExp data. |
| 4024 __ bind(&success); | 4034 __ bind(&success); |
| 4025 __ mov(eax, Operand(esp, kJSRegExpOffset)); | 4035 __ mov(eax, Operand(esp, kJSRegExpOffset)); |
| 4026 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); | 4036 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); |
| 4027 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); | 4037 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); |
| 4028 // Calculate number of capture registers (number_of_captures + 1) * 2. | 4038 // Calculate number of capture registers (number_of_captures + 1) * 2. |
| 4029 STATIC_ASSERT(kSmiTag == 0); | 4039 STATIC_ASSERT(kSmiTag == 0); |
| 4030 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); | 4040 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4115 edx, // Scratch register | 4125 edx, // Scratch register |
| 4116 &slowcase, | 4126 &slowcase, |
| 4117 TAG_OBJECT); | 4127 TAG_OBJECT); |
| 4118 // eax: Start of allocated area, object-tagged. | 4128 // eax: Start of allocated area, object-tagged. |
| 4119 | 4129 |
| 4120 // Set JSArray map to global.regexp_result_map(). | 4130 // Set JSArray map to global.regexp_result_map(). |
| 4121 // Set empty properties FixedArray. | 4131 // Set empty properties FixedArray. |
| 4122 // Set elements to point to FixedArray allocated right after the JSArray. | 4132 // Set elements to point to FixedArray allocated right after the JSArray. |
| 4123 // Interleave operations for better latency. | 4133 // Interleave operations for better latency. |
| 4124 __ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX)); | 4134 __ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX)); |
| 4125 __ mov(ecx, Immediate(Factory::empty_fixed_array())); | 4135 __ mov(ecx, Immediate(FACTORY->empty_fixed_array())); |
| 4126 __ lea(ebx, Operand(eax, JSRegExpResult::kSize)); | 4136 __ lea(ebx, Operand(eax, JSRegExpResult::kSize)); |
| 4127 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset)); | 4137 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset)); |
| 4128 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx); | 4138 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx); |
| 4129 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx); | 4139 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx); |
| 4130 __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX)); | 4140 __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX)); |
| 4131 __ mov(FieldOperand(eax, HeapObject::kMapOffset), edx); | 4141 __ mov(FieldOperand(eax, HeapObject::kMapOffset), edx); |
| 4132 | 4142 |
| 4133 // Set input, index and length fields from arguments. | 4143 // Set input, index and length fields from arguments. |
| 4134 __ mov(ecx, Operand(esp, kPointerSize * 1)); | 4144 __ mov(ecx, Operand(esp, kPointerSize * 1)); |
| 4135 __ mov(FieldOperand(eax, JSRegExpResult::kInputOffset), ecx); | 4145 __ mov(FieldOperand(eax, JSRegExpResult::kInputOffset), ecx); |
| 4136 __ mov(ecx, Operand(esp, kPointerSize * 2)); | 4146 __ mov(ecx, Operand(esp, kPointerSize * 2)); |
| 4137 __ mov(FieldOperand(eax, JSRegExpResult::kIndexOffset), ecx); | 4147 __ mov(FieldOperand(eax, JSRegExpResult::kIndexOffset), ecx); |
| 4138 __ mov(ecx, Operand(esp, kPointerSize * 3)); | 4148 __ mov(ecx, Operand(esp, kPointerSize * 3)); |
| 4139 __ mov(FieldOperand(eax, JSArray::kLengthOffset), ecx); | 4149 __ mov(FieldOperand(eax, JSArray::kLengthOffset), ecx); |
| 4140 | 4150 |
| 4141 // Fill out the elements FixedArray. | 4151 // Fill out the elements FixedArray. |
| 4142 // eax: JSArray. | 4152 // eax: JSArray. |
| 4143 // ebx: FixedArray. | 4153 // ebx: FixedArray. |
| 4144 // ecx: Number of elements in array, as smi. | 4154 // ecx: Number of elements in array, as smi. |
| 4145 | 4155 |
| 4146 // Set map. | 4156 // Set map. |
| 4147 __ mov(FieldOperand(ebx, HeapObject::kMapOffset), | 4157 __ mov(FieldOperand(ebx, HeapObject::kMapOffset), |
| 4148 Immediate(Factory::fixed_array_map())); | 4158 Immediate(FACTORY->fixed_array_map())); |
| 4149 // Set length. | 4159 // Set length. |
| 4150 __ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx); | 4160 __ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx); |
| 4151 // Fill contents of fixed-array with the-hole. | 4161 // Fill contents of fixed-array with the-hole. |
| 4152 __ SmiUntag(ecx); | 4162 __ SmiUntag(ecx); |
| 4153 __ mov(edx, Immediate(Factory::the_hole_value())); | 4163 __ mov(edx, Immediate(FACTORY->the_hole_value())); |
| 4154 __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize)); | 4164 __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize)); |
| 4155 // Fill fixed array elements with hole. | 4165 // Fill fixed array elements with hole. |
| 4156 // eax: JSArray. | 4166 // eax: JSArray. |
| 4157 // ecx: Number of elements to fill. | 4167 // ecx: Number of elements to fill. |
| 4158 // ebx: Start of elements in FixedArray. | 4168 // ebx: Start of elements in FixedArray. |
| 4159 // edx: the hole. | 4169 // edx: the hole. |
| 4160 Label loop; | 4170 Label loop; |
| 4161 __ test(ecx, Operand(ecx)); | 4171 __ test(ecx, Operand(ecx)); |
| 4162 __ bind(&loop); | 4172 __ bind(&loop); |
| 4163 __ j(less_equal, &done); // Jump if ecx is negative or zero. | 4173 __ j(less_equal, &done); // Jump if ecx is negative or zero. |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4208 } else { | 4218 } else { |
| 4209 NearLabel not_smi, hash_calculated; | 4219 NearLabel not_smi, hash_calculated; |
| 4210 STATIC_ASSERT(kSmiTag == 0); | 4220 STATIC_ASSERT(kSmiTag == 0); |
| 4211 __ test(object, Immediate(kSmiTagMask)); | 4221 __ test(object, Immediate(kSmiTagMask)); |
| 4212 __ j(not_zero, ¬_smi); | 4222 __ j(not_zero, ¬_smi); |
| 4213 __ mov(scratch, object); | 4223 __ mov(scratch, object); |
| 4214 __ SmiUntag(scratch); | 4224 __ SmiUntag(scratch); |
| 4215 __ jmp(&smi_hash_calculated); | 4225 __ jmp(&smi_hash_calculated); |
| 4216 __ bind(¬_smi); | 4226 __ bind(¬_smi); |
| 4217 __ cmp(FieldOperand(object, HeapObject::kMapOffset), | 4227 __ cmp(FieldOperand(object, HeapObject::kMapOffset), |
| 4218 Factory::heap_number_map()); | 4228 FACTORY->heap_number_map()); |
| 4219 __ j(not_equal, not_found); | 4229 __ j(not_equal, not_found); |
| 4220 STATIC_ASSERT(8 == kDoubleSize); | 4230 STATIC_ASSERT(8 == kDoubleSize); |
| 4221 __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); | 4231 __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); |
| 4222 __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); | 4232 __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); |
| 4223 // Object is heap number and hash is now in scratch. Calculate cache index. | 4233 // Object is heap number and hash is now in scratch. Calculate cache index. |
| 4224 __ and_(scratch, Operand(mask)); | 4234 __ and_(scratch, Operand(mask)); |
| 4225 Register index = scratch; | 4235 Register index = scratch; |
| 4226 Register probe = mask; | 4236 Register probe = mask; |
| 4227 __ mov(probe, | 4237 __ mov(probe, |
| 4228 FieldOperand(number_string_cache, | 4238 FieldOperand(number_string_cache, |
| 4229 index, | 4239 index, |
| 4230 times_twice_pointer_size, | 4240 times_twice_pointer_size, |
| 4231 FixedArray::kHeaderSize)); | 4241 FixedArray::kHeaderSize)); |
| 4232 __ test(probe, Immediate(kSmiTagMask)); | 4242 __ test(probe, Immediate(kSmiTagMask)); |
| 4233 __ j(zero, not_found); | 4243 __ j(zero, not_found); |
| 4234 if (CpuFeatures::IsSupported(SSE2)) { | 4244 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 4235 CpuFeatures::Scope fscope(SSE2); | 4245 CpuFeatures::Scope fscope(SSE2); |
| 4236 __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); | 4246 __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); |
| 4237 __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset)); | 4247 __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset)); |
| 4238 __ ucomisd(xmm0, xmm1); | 4248 __ ucomisd(xmm0, xmm1); |
| 4239 } else { | 4249 } else { |
| 4240 __ fld_d(FieldOperand(object, HeapNumber::kValueOffset)); | 4250 __ fld_d(FieldOperand(object, HeapNumber::kValueOffset)); |
| 4241 __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); | 4251 __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); |
| 4242 __ FCmp(); | 4252 __ FCmp(); |
| 4243 } | 4253 } |
| 4244 __ j(parity_even, not_found); // Bail out if NaN is involved. | 4254 __ j(parity_even, not_found); // Bail out if NaN is involved. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 4258 FixedArray::kHeaderSize)); | 4268 FixedArray::kHeaderSize)); |
| 4259 __ j(not_equal, not_found); | 4269 __ j(not_equal, not_found); |
| 4260 | 4270 |
| 4261 // Get the result from the cache. | 4271 // Get the result from the cache. |
| 4262 __ bind(&load_result_from_cache); | 4272 __ bind(&load_result_from_cache); |
| 4263 __ mov(result, | 4273 __ mov(result, |
| 4264 FieldOperand(number_string_cache, | 4274 FieldOperand(number_string_cache, |
| 4265 index, | 4275 index, |
| 4266 times_twice_pointer_size, | 4276 times_twice_pointer_size, |
| 4267 FixedArray::kHeaderSize + kPointerSize)); | 4277 FixedArray::kHeaderSize + kPointerSize)); |
| 4268 __ IncrementCounter(&Counters::number_to_string_native, 1); | 4278 __ IncrementCounter(COUNTERS->number_to_string_native(), 1); |
| 4269 } | 4279 } |
| 4270 | 4280 |
| 4271 | 4281 |
| 4272 void NumberToStringStub::Generate(MacroAssembler* masm) { | 4282 void NumberToStringStub::Generate(MacroAssembler* masm) { |
| 4273 Label runtime; | 4283 Label runtime; |
| 4274 | 4284 |
| 4275 __ mov(ebx, Operand(esp, kPointerSize)); | 4285 __ mov(ebx, Operand(esp, kPointerSize)); |
| 4276 | 4286 |
| 4277 // Generate code to lookup number in the number string cache. | 4287 // Generate code to lookup number in the number string cache. |
| 4278 GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime); | 4288 GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4324 // for NaN and undefined. | 4334 // for NaN and undefined. |
| 4325 { | 4335 { |
| 4326 Label not_identical; | 4336 Label not_identical; |
| 4327 __ cmp(eax, Operand(edx)); | 4337 __ cmp(eax, Operand(edx)); |
| 4328 __ j(not_equal, ¬_identical); | 4338 __ j(not_equal, ¬_identical); |
| 4329 | 4339 |
| 4330 if (cc_ != equal) { | 4340 if (cc_ != equal) { |
| 4331 // Check for undefined. undefined OP undefined is false even though | 4341 // Check for undefined. undefined OP undefined is false even though |
| 4332 // undefined == undefined. | 4342 // undefined == undefined. |
| 4333 NearLabel check_for_nan; | 4343 NearLabel check_for_nan; |
| 4334 __ cmp(edx, Factory::undefined_value()); | 4344 __ cmp(edx, FACTORY->undefined_value()); |
| 4335 __ j(not_equal, &check_for_nan); | 4345 __ j(not_equal, &check_for_nan); |
| 4336 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); | 4346 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); |
| 4337 __ ret(0); | 4347 __ ret(0); |
| 4338 __ bind(&check_for_nan); | 4348 __ bind(&check_for_nan); |
| 4339 } | 4349 } |
| 4340 | 4350 |
| 4341 // Test for NaN. Sadly, we can't just compare to Factory::nan_value(), | 4351 // Test for NaN. Sadly, we can't just compare to FACTORY->nan_value(), |
| 4342 // so we do the second best thing - test it ourselves. | 4352 // so we do the second best thing - test it ourselves. |
| 4343 // Note: if cc_ != equal, never_nan_nan_ is not used. | 4353 // Note: if cc_ != equal, never_nan_nan_ is not used. |
| 4344 if (never_nan_nan_ && (cc_ == equal)) { | 4354 if (never_nan_nan_ && (cc_ == equal)) { |
| 4345 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 4355 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
| 4346 __ ret(0); | 4356 __ ret(0); |
| 4347 } else { | 4357 } else { |
| 4348 NearLabel heap_number; | 4358 NearLabel heap_number; |
| 4349 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 4359 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 4350 Immediate(Factory::heap_number_map())); | 4360 Immediate(FACTORY->heap_number_map())); |
| 4351 __ j(equal, &heap_number); | 4361 __ j(equal, &heap_number); |
| 4352 if (cc_ != equal) { | 4362 if (cc_ != equal) { |
| 4353 // Call runtime on identical JSObjects. Otherwise return equal. | 4363 // Call runtime on identical JSObjects. Otherwise return equal. |
| 4354 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); | 4364 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx); |
| 4355 __ j(above_equal, ¬_identical); | 4365 __ j(above_equal, ¬_identical); |
| 4356 } | 4366 } |
| 4357 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 4367 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
| 4358 __ ret(0); | 4368 __ ret(0); |
| 4359 | 4369 |
| 4360 __ bind(&heap_number); | 4370 __ bind(&heap_number); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4417 // ecx still holds eax & kSmiTag, which is either zero or one. | 4427 // ecx still holds eax & kSmiTag, which is either zero or one. |
| 4418 __ sub(Operand(ecx), Immediate(0x01)); | 4428 __ sub(Operand(ecx), Immediate(0x01)); |
| 4419 __ mov(ebx, edx); | 4429 __ mov(ebx, edx); |
| 4420 __ xor_(ebx, Operand(eax)); | 4430 __ xor_(ebx, Operand(eax)); |
| 4421 __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx. | 4431 __ and_(ebx, Operand(ecx)); // ebx holds either 0 or eax ^ edx. |
| 4422 __ xor_(ebx, Operand(eax)); | 4432 __ xor_(ebx, Operand(eax)); |
| 4423 // if eax was smi, ebx is now edx, else eax. | 4433 // if eax was smi, ebx is now edx, else eax. |
| 4424 | 4434 |
| 4425 // Check if the non-smi operand is a heap number. | 4435 // Check if the non-smi operand is a heap number. |
| 4426 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 4436 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 4427 Immediate(Factory::heap_number_map())); | 4437 Immediate(FACTORY->heap_number_map())); |
| 4428 // If heap number, handle it in the slow case. | 4438 // If heap number, handle it in the slow case. |
| 4429 __ j(equal, &slow); | 4439 __ j(equal, &slow); |
| 4430 // Return non-equal (ebx is not zero) | 4440 // Return non-equal (ebx is not zero) |
| 4431 __ mov(eax, ebx); | 4441 __ mov(eax, ebx); |
| 4432 __ ret(0); | 4442 __ ret(0); |
| 4433 | 4443 |
| 4434 __ bind(¬_smis); | 4444 __ bind(¬_smis); |
| 4435 // If either operand is a JSObject or an oddball value, then they are not | 4445 // If either operand is a JSObject or an oddball value, then they are not |
| 4436 // equal since their pointers are different | 4446 // equal since their pointers are different |
| 4437 // There is no test for undetectability in strict equality. | 4447 // There is no test for undetectability in strict equality. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 4462 __ j(equal, &return_not_equal); | 4472 __ j(equal, &return_not_equal); |
| 4463 | 4473 |
| 4464 // Fall through to the general case. | 4474 // Fall through to the general case. |
| 4465 __ bind(&slow); | 4475 __ bind(&slow); |
| 4466 } | 4476 } |
| 4467 | 4477 |
| 4468 // Generate the number comparison code. | 4478 // Generate the number comparison code. |
| 4469 if (include_number_compare_) { | 4479 if (include_number_compare_) { |
| 4470 Label non_number_comparison; | 4480 Label non_number_comparison; |
| 4471 Label unordered; | 4481 Label unordered; |
| 4472 if (CpuFeatures::IsSupported(SSE2)) { | 4482 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 4473 CpuFeatures::Scope use_sse2(SSE2); | 4483 CpuFeatures::Scope use_sse2(SSE2); |
| 4474 CpuFeatures::Scope use_cmov(CMOV); | 4484 CpuFeatures::Scope use_cmov(CMOV); |
| 4475 | 4485 |
| 4476 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); | 4486 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); |
| 4477 __ ucomisd(xmm0, xmm1); | 4487 __ ucomisd(xmm0, xmm1); |
| 4478 | 4488 |
| 4479 // Don't base result on EFLAGS when a NaN is involved. | 4489 // Don't base result on EFLAGS when a NaN is involved. |
| 4480 __ j(parity_even, &unordered, not_taken); | 4490 __ j(parity_even, &unordered, not_taken); |
| 4481 // Return a result of -1, 0, or 1, based on EFLAGS. | 4491 // Return a result of -1, 0, or 1, based on EFLAGS. |
| 4482 __ mov(eax, 0); // equal | 4492 __ mov(eax, 0); // equal |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4681 __ InvokeFunction(edi, actual, JUMP_FUNCTION); | 4691 __ InvokeFunction(edi, actual, JUMP_FUNCTION); |
| 4682 | 4692 |
| 4683 // Slow-case: Non-function called. | 4693 // Slow-case: Non-function called. |
| 4684 __ bind(&slow); | 4694 __ bind(&slow); |
| 4685 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead | 4695 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead |
| 4686 // of the original receiver from the call site). | 4696 // of the original receiver from the call site). |
| 4687 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi); | 4697 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi); |
| 4688 __ Set(eax, Immediate(argc_)); | 4698 __ Set(eax, Immediate(argc_)); |
| 4689 __ Set(ebx, Immediate(0)); | 4699 __ Set(ebx, Immediate(0)); |
| 4690 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); | 4700 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); |
| 4691 Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); | 4701 Handle<Code> adaptor(Isolate::Current()->builtins()->builtin( |
| 4702 Builtins::ArgumentsAdaptorTrampoline)); |
| 4692 __ jmp(adaptor, RelocInfo::CODE_TARGET); | 4703 __ jmp(adaptor, RelocInfo::CODE_TARGET); |
| 4693 } | 4704 } |
| 4694 | 4705 |
| 4695 | 4706 |
| 4696 bool CEntryStub::NeedsImmovableCode() { | 4707 bool CEntryStub::NeedsImmovableCode() { |
| 4697 return false; | 4708 return false; |
| 4698 } | 4709 } |
| 4699 | 4710 |
| 4700 | 4711 |
| 4701 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { | 4712 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4735 | 4746 |
| 4736 ExternalReference scope_depth = | 4747 ExternalReference scope_depth = |
| 4737 ExternalReference::heap_always_allocate_scope_depth(); | 4748 ExternalReference::heap_always_allocate_scope_depth(); |
| 4738 if (always_allocate_scope) { | 4749 if (always_allocate_scope) { |
| 4739 __ inc(Operand::StaticVariable(scope_depth)); | 4750 __ inc(Operand::StaticVariable(scope_depth)); |
| 4740 } | 4751 } |
| 4741 | 4752 |
| 4742 // Call C function. | 4753 // Call C function. |
| 4743 __ mov(Operand(esp, 0 * kPointerSize), edi); // argc. | 4754 __ mov(Operand(esp, 0 * kPointerSize), edi); // argc. |
| 4744 __ mov(Operand(esp, 1 * kPointerSize), esi); // argv. | 4755 __ mov(Operand(esp, 1 * kPointerSize), esi); // argv. |
| 4756 __ mov(Operand(esp, 2 * kPointerSize), |
| 4757 Immediate(ExternalReference::isolate_address())); |
| 4745 __ call(Operand(ebx)); | 4758 __ call(Operand(ebx)); |
| 4746 // Result is in eax or edx:eax - do not destroy these registers! | 4759 // Result is in eax or edx:eax - do not destroy these registers! |
| 4747 | 4760 |
| 4748 if (always_allocate_scope) { | 4761 if (always_allocate_scope) { |
| 4749 __ dec(Operand::StaticVariable(scope_depth)); | 4762 __ dec(Operand::StaticVariable(scope_depth)); |
| 4750 } | 4763 } |
| 4751 | 4764 |
| 4752 // Make sure we're not trying to return 'the hole' from the runtime | 4765 // Make sure we're not trying to return 'the hole' from the runtime |
| 4753 // call as this may lead to crashes in the IC code later. | 4766 // call as this may lead to crashes in the IC code later. |
| 4754 if (FLAG_debug_code) { | 4767 if (FLAG_debug_code) { |
| 4755 NearLabel okay; | 4768 NearLabel okay; |
| 4756 __ cmp(eax, Factory::the_hole_value()); | 4769 __ cmp(eax, FACTORY->the_hole_value()); |
| 4757 __ j(not_equal, &okay); | 4770 __ j(not_equal, &okay); |
| 4758 __ int3(); | 4771 __ int3(); |
| 4759 __ bind(&okay); | 4772 __ bind(&okay); |
| 4760 } | 4773 } |
| 4761 | 4774 |
| 4762 // Check for failure result. | 4775 // Check for failure result. |
| 4763 Label failure_returned; | 4776 Label failure_returned; |
| 4764 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); | 4777 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); |
| 4765 __ lea(ecx, Operand(eax, 1)); | 4778 __ lea(ecx, Operand(eax, 1)); |
| 4766 // Lower 2 bits of ecx are 0 iff eax has failure tag. | 4779 // Lower 2 bits of ecx are 0 iff eax has failure tag. |
| 4767 __ test(ecx, Immediate(kFailureTagMask)); | 4780 __ test(ecx, Immediate(kFailureTagMask)); |
| 4768 __ j(zero, &failure_returned, not_taken); | 4781 __ j(zero, &failure_returned, not_taken); |
| 4769 | 4782 |
| 4770 ExternalReference pending_exception_address(Top::k_pending_exception_address); | 4783 ExternalReference pending_exception_address( |
| 4784 Isolate::k_pending_exception_address); |
| 4771 | 4785 |
| 4772 // Check that there is no pending exception, otherwise we | 4786 // Check that there is no pending exception, otherwise we |
| 4773 // should have returned some failure value. | 4787 // should have returned some failure value. |
| 4774 if (FLAG_debug_code) { | 4788 if (FLAG_debug_code) { |
| 4775 __ push(edx); | 4789 __ push(edx); |
| 4776 __ mov(edx, Operand::StaticVariable( | 4790 __ mov(edx, Operand::StaticVariable( |
| 4777 ExternalReference::the_hole_value_location())); | 4791 ExternalReference::the_hole_value_location())); |
| 4778 NearLabel okay; | 4792 NearLabel okay; |
| 4779 __ cmp(edx, Operand::StaticVariable(pending_exception_address)); | 4793 __ cmp(edx, Operand::StaticVariable(pending_exception_address)); |
| 4780 // Cannot use check here as it attempts to generate call into runtime. | 4794 // Cannot use check here as it attempts to generate call into runtime. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 4802 __ j(equal, throw_out_of_memory_exception); | 4816 __ j(equal, throw_out_of_memory_exception); |
| 4803 | 4817 |
| 4804 // Retrieve the pending exception and clear the variable. | 4818 // Retrieve the pending exception and clear the variable. |
| 4805 __ mov(eax, Operand::StaticVariable(pending_exception_address)); | 4819 __ mov(eax, Operand::StaticVariable(pending_exception_address)); |
| 4806 __ mov(edx, | 4820 __ mov(edx, |
| 4807 Operand::StaticVariable(ExternalReference::the_hole_value_location())); | 4821 Operand::StaticVariable(ExternalReference::the_hole_value_location())); |
| 4808 __ mov(Operand::StaticVariable(pending_exception_address), edx); | 4822 __ mov(Operand::StaticVariable(pending_exception_address), edx); |
| 4809 | 4823 |
| 4810 // Special handling of termination exceptions which are uncatchable | 4824 // Special handling of termination exceptions which are uncatchable |
| 4811 // by javascript code. | 4825 // by javascript code. |
| 4812 __ cmp(eax, Factory::termination_exception()); | 4826 __ cmp(eax, FACTORY->termination_exception()); |
| 4813 __ j(equal, throw_termination_exception); | 4827 __ j(equal, throw_termination_exception); |
| 4814 | 4828 |
| 4815 // Handle normal exception. | 4829 // Handle normal exception. |
| 4816 __ jmp(throw_normal_exception); | 4830 __ jmp(throw_normal_exception); |
| 4817 | 4831 |
| 4818 // Retry. | 4832 // Retry. |
| 4819 __ bind(&retry); | 4833 __ bind(&retry); |
| 4820 } | 4834 } |
| 4821 | 4835 |
| 4822 | 4836 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4902 // Push marker in two places. | 4916 // Push marker in two places. |
| 4903 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; | 4917 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; |
| 4904 __ push(Immediate(Smi::FromInt(marker))); // context slot | 4918 __ push(Immediate(Smi::FromInt(marker))); // context slot |
| 4905 __ push(Immediate(Smi::FromInt(marker))); // function slot | 4919 __ push(Immediate(Smi::FromInt(marker))); // function slot |
| 4906 // Save callee-saved registers (C calling conventions). | 4920 // Save callee-saved registers (C calling conventions). |
| 4907 __ push(edi); | 4921 __ push(edi); |
| 4908 __ push(esi); | 4922 __ push(esi); |
| 4909 __ push(ebx); | 4923 __ push(ebx); |
| 4910 | 4924 |
| 4911 // Save copies of the top frame descriptor on the stack. | 4925 // Save copies of the top frame descriptor on the stack. |
| 4912 ExternalReference c_entry_fp(Top::k_c_entry_fp_address); | 4926 ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address); |
| 4913 __ push(Operand::StaticVariable(c_entry_fp)); | 4927 __ push(Operand::StaticVariable(c_entry_fp)); |
| 4914 | 4928 |
| 4915 #ifdef ENABLE_LOGGING_AND_PROFILING | 4929 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 4916 // If this is the outermost JS call, set js_entry_sp value. | 4930 // If this is the outermost JS call, set js_entry_sp value. |
| 4917 ExternalReference js_entry_sp(Top::k_js_entry_sp_address); | 4931 ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address); |
| 4918 __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0)); | 4932 __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0)); |
| 4919 __ j(not_equal, ¬_outermost_js); | 4933 __ j(not_equal, ¬_outermost_js); |
| 4920 __ mov(Operand::StaticVariable(js_entry_sp), ebp); | 4934 __ mov(Operand::StaticVariable(js_entry_sp), ebp); |
| 4921 __ bind(¬_outermost_js); | 4935 __ bind(¬_outermost_js); |
| 4922 #endif | 4936 #endif |
| 4923 | 4937 |
| 4924 // Call a faked try-block that does the invoke. | 4938 // Call a faked try-block that does the invoke. |
| 4925 __ call(&invoke); | 4939 __ call(&invoke); |
| 4926 | 4940 |
| 4927 // Caught exception: Store result (exception) in the pending | 4941 // Caught exception: Store result (exception) in the pending |
| 4928 // exception field in the JSEnv and return a failure sentinel. | 4942 // exception field in the JSEnv and return a failure sentinel. |
| 4929 ExternalReference pending_exception(Top::k_pending_exception_address); | 4943 ExternalReference pending_exception(Isolate::k_pending_exception_address); |
| 4930 __ mov(Operand::StaticVariable(pending_exception), eax); | 4944 __ mov(Operand::StaticVariable(pending_exception), eax); |
| 4931 __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception())); | 4945 __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception())); |
| 4932 __ jmp(&exit); | 4946 __ jmp(&exit); |
| 4933 | 4947 |
| 4934 // Invoke: Link this frame into the handler chain. | 4948 // Invoke: Link this frame into the handler chain. |
| 4935 __ bind(&invoke); | 4949 __ bind(&invoke); |
| 4936 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); | 4950 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); |
| 4937 | 4951 |
| 4938 // Clear any pending exceptions. | 4952 // Clear any pending exceptions. |
| 4939 __ mov(edx, | 4953 __ mov(edx, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 4952 __ mov(edx, Immediate(construct_entry)); | 4966 __ mov(edx, Immediate(construct_entry)); |
| 4953 } else { | 4967 } else { |
| 4954 ExternalReference entry(Builtins::JSEntryTrampoline); | 4968 ExternalReference entry(Builtins::JSEntryTrampoline); |
| 4955 __ mov(edx, Immediate(entry)); | 4969 __ mov(edx, Immediate(entry)); |
| 4956 } | 4970 } |
| 4957 __ mov(edx, Operand(edx, 0)); // deref address | 4971 __ mov(edx, Operand(edx, 0)); // deref address |
| 4958 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); | 4972 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); |
| 4959 __ call(Operand(edx)); | 4973 __ call(Operand(edx)); |
| 4960 | 4974 |
| 4961 // Unlink this frame from the handler chain. | 4975 // Unlink this frame from the handler chain. |
| 4962 __ pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address))); | 4976 __ pop(Operand::StaticVariable(ExternalReference( |
| 4977 Isolate::k_handler_address))); |
| 4963 // Pop next_sp. | 4978 // Pop next_sp. |
| 4964 __ add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize)); | 4979 __ add(Operand(esp), Immediate(StackHandlerConstants::kSize - kPointerSize)); |
| 4965 | 4980 |
| 4966 #ifdef ENABLE_LOGGING_AND_PROFILING | 4981 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 4967 // If current EBP value is the same as js_entry_sp value, it means that | 4982 // If current EBP value is the same as js_entry_sp value, it means that |
| 4968 // the current function is the outermost. | 4983 // the current function is the outermost. |
| 4969 __ cmp(ebp, Operand::StaticVariable(js_entry_sp)); | 4984 __ cmp(ebp, Operand::StaticVariable(js_entry_sp)); |
| 4970 __ j(not_equal, ¬_outermost_js_2); | 4985 __ j(not_equal, ¬_outermost_js_2); |
| 4971 __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); | 4986 __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); |
| 4972 __ bind(¬_outermost_js_2); | 4987 __ bind(¬_outermost_js_2); |
| 4973 #endif | 4988 #endif |
| 4974 | 4989 |
| 4975 // Restore the top frame descriptor from the stack. | 4990 // Restore the top frame descriptor from the stack. |
| 4976 __ bind(&exit); | 4991 __ bind(&exit); |
| 4977 __ pop(Operand::StaticVariable(ExternalReference(Top::k_c_entry_fp_address))); | 4992 __ pop(Operand::StaticVariable(ExternalReference( |
| 4993 Isolate::k_c_entry_fp_address))); |
| 4978 | 4994 |
| 4979 // Restore callee-saved registers (C calling conventions). | 4995 // Restore callee-saved registers (C calling conventions). |
| 4980 __ pop(ebx); | 4996 __ pop(ebx); |
| 4981 __ pop(esi); | 4997 __ pop(esi); |
| 4982 __ pop(edi); | 4998 __ pop(edi); |
| 4983 __ add(Operand(esp), Immediate(2 * kPointerSize)); // remove markers | 4999 __ add(Operand(esp), Immediate(2 * kPointerSize)); // remove markers |
| 4984 | 5000 |
| 4985 // Restore frame pointer and return. | 5001 // Restore frame pointer and return. |
| 4986 __ pop(ebp); | 5002 __ pop(ebp); |
| 4987 __ ret(0); | 5003 __ ret(0); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5092 __ mov(Operand(scratch, kDeltaToCmpImmediate), map); | 5108 __ mov(Operand(scratch, kDeltaToCmpImmediate), map); |
| 5093 } | 5109 } |
| 5094 | 5110 |
| 5095 // Loop through the prototype chain of the object looking for the function | 5111 // Loop through the prototype chain of the object looking for the function |
| 5096 // prototype. | 5112 // prototype. |
| 5097 __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset)); | 5113 __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset)); |
| 5098 NearLabel loop, is_instance, is_not_instance; | 5114 NearLabel loop, is_instance, is_not_instance; |
| 5099 __ bind(&loop); | 5115 __ bind(&loop); |
| 5100 __ cmp(scratch, Operand(prototype)); | 5116 __ cmp(scratch, Operand(prototype)); |
| 5101 __ j(equal, &is_instance); | 5117 __ j(equal, &is_instance); |
| 5102 __ cmp(Operand(scratch), Immediate(Factory::null_value())); | 5118 __ cmp(Operand(scratch), Immediate(FACTORY->null_value())); |
| 5103 __ j(equal, &is_not_instance); | 5119 __ j(equal, &is_not_instance); |
| 5104 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); | 5120 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
| 5105 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); | 5121 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); |
| 5106 __ jmp(&loop); | 5122 __ jmp(&loop); |
| 5107 | 5123 |
| 5108 __ bind(&is_instance); | 5124 __ bind(&is_instance); |
| 5109 if (!HasCallSiteInlineCheck()) { | 5125 if (!HasCallSiteInlineCheck()) { |
| 5110 __ Set(eax, Immediate(0)); | 5126 __ Set(eax, Immediate(0)); |
| 5111 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 5127 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
| 5112 __ mov(Operand::StaticArray(scratch, | 5128 __ mov(Operand::StaticArray(scratch, |
| 5113 times_pointer_size, roots_address), eax); | 5129 times_pointer_size, roots_address), eax); |
| 5114 } else { | 5130 } else { |
| 5115 // Get return address and delta to inlined map check. | 5131 // Get return address and delta to inlined map check. |
| 5116 __ mov(eax, Factory::true_value()); | 5132 __ mov(eax, FACTORY->true_value()); |
| 5117 __ mov(scratch, Operand(esp, 0 * kPointerSize)); | 5133 __ mov(scratch, Operand(esp, 0 * kPointerSize)); |
| 5118 __ sub(scratch, Operand(esp, 1 * kPointerSize)); | 5134 __ sub(scratch, Operand(esp, 1 * kPointerSize)); |
| 5119 if (FLAG_debug_code) { | 5135 if (FLAG_debug_code) { |
| 5120 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); | 5136 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); |
| 5121 __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); | 5137 __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); |
| 5122 } | 5138 } |
| 5123 __ mov(Operand(scratch, kDeltaToMovImmediate), eax); | 5139 __ mov(Operand(scratch, kDeltaToMovImmediate), eax); |
| 5124 if (!ReturnTrueFalseObject()) { | 5140 if (!ReturnTrueFalseObject()) { |
| 5125 __ Set(eax, Immediate(0)); | 5141 __ Set(eax, Immediate(0)); |
| 5126 } | 5142 } |
| 5127 } | 5143 } |
| 5128 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 5144 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| 5129 | 5145 |
| 5130 __ bind(&is_not_instance); | 5146 __ bind(&is_not_instance); |
| 5131 if (!HasCallSiteInlineCheck()) { | 5147 if (!HasCallSiteInlineCheck()) { |
| 5132 __ Set(eax, Immediate(Smi::FromInt(1))); | 5148 __ Set(eax, Immediate(Smi::FromInt(1))); |
| 5133 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 5149 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
| 5134 __ mov(Operand::StaticArray( | 5150 __ mov(Operand::StaticArray( |
| 5135 scratch, times_pointer_size, roots_address), eax); | 5151 scratch, times_pointer_size, roots_address), eax); |
| 5136 } else { | 5152 } else { |
| 5137 // Get return address and delta to inlined map check. | 5153 // Get return address and delta to inlined map check. |
| 5138 __ mov(eax, Factory::false_value()); | 5154 __ mov(eax, FACTORY->false_value()); |
| 5139 __ mov(scratch, Operand(esp, 0 * kPointerSize)); | 5155 __ mov(scratch, Operand(esp, 0 * kPointerSize)); |
| 5140 __ sub(scratch, Operand(esp, 1 * kPointerSize)); | 5156 __ sub(scratch, Operand(esp, 1 * kPointerSize)); |
| 5141 if (FLAG_debug_code) { | 5157 if (FLAG_debug_code) { |
| 5142 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); | 5158 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); |
| 5143 __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); | 5159 __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); |
| 5144 } | 5160 } |
| 5145 __ mov(Operand(scratch, kDeltaToMovImmediate), eax); | 5161 __ mov(Operand(scratch, kDeltaToMovImmediate), eax); |
| 5146 if (!ReturnTrueFalseObject()) { | 5162 if (!ReturnTrueFalseObject()) { |
| 5147 __ Set(eax, Immediate(Smi::FromInt(1))); | 5163 __ Set(eax, Immediate(Smi::FromInt(1))); |
| 5148 } | 5164 } |
| 5149 } | 5165 } |
| 5150 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 5166 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| 5151 | 5167 |
| 5152 Label object_not_null, object_not_null_or_smi; | 5168 Label object_not_null, object_not_null_or_smi; |
| 5153 __ bind(¬_js_object); | 5169 __ bind(¬_js_object); |
| 5154 // Before null, smi and string value checks, check that the rhs is a function | 5170 // Before null, smi and string value checks, check that the rhs is a function |
| 5155 // as for a non-function rhs an exception needs to be thrown. | 5171 // as for a non-function rhs an exception needs to be thrown. |
| 5156 __ test(function, Immediate(kSmiTagMask)); | 5172 __ test(function, Immediate(kSmiTagMask)); |
| 5157 __ j(zero, &slow, not_taken); | 5173 __ j(zero, &slow, not_taken); |
| 5158 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); | 5174 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); |
| 5159 __ j(not_equal, &slow, not_taken); | 5175 __ j(not_equal, &slow, not_taken); |
| 5160 | 5176 |
| 5161 // Null is not instance of anything. | 5177 // Null is not instance of anything. |
| 5162 __ cmp(object, Factory::null_value()); | 5178 __ cmp(object, FACTORY->null_value()); |
| 5163 __ j(not_equal, &object_not_null); | 5179 __ j(not_equal, &object_not_null); |
| 5164 __ Set(eax, Immediate(Smi::FromInt(1))); | 5180 __ Set(eax, Immediate(Smi::FromInt(1))); |
| 5165 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 5181 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| 5166 | 5182 |
| 5167 __ bind(&object_not_null); | 5183 __ bind(&object_not_null); |
| 5168 // Smi values is not instance of anything. | 5184 // Smi values is not instance of anything. |
| 5169 __ test(object, Immediate(kSmiTagMask)); | 5185 __ test(object, Immediate(kSmiTagMask)); |
| 5170 __ j(not_zero, &object_not_null_or_smi, not_taken); | 5186 __ j(not_zero, &object_not_null_or_smi, not_taken); |
| 5171 __ Set(eax, Immediate(Smi::FromInt(1))); | 5187 __ Set(eax, Immediate(Smi::FromInt(1))); |
| 5172 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 5188 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 5193 } else { | 5209 } else { |
| 5194 // Call the builtin and convert 0/1 to true/false. | 5210 // Call the builtin and convert 0/1 to true/false. |
| 5195 __ EnterInternalFrame(); | 5211 __ EnterInternalFrame(); |
| 5196 __ push(object); | 5212 __ push(object); |
| 5197 __ push(function); | 5213 __ push(function); |
| 5198 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); | 5214 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); |
| 5199 __ LeaveInternalFrame(); | 5215 __ LeaveInternalFrame(); |
| 5200 NearLabel true_value, done; | 5216 NearLabel true_value, done; |
| 5201 __ test(eax, Operand(eax)); | 5217 __ test(eax, Operand(eax)); |
| 5202 __ j(zero, &true_value); | 5218 __ j(zero, &true_value); |
| 5203 __ mov(eax, Factory::false_value()); | 5219 __ mov(eax, FACTORY->false_value()); |
| 5204 __ jmp(&done); | 5220 __ jmp(&done); |
| 5205 __ bind(&true_value); | 5221 __ bind(&true_value); |
| 5206 __ mov(eax, Factory::true_value()); | 5222 __ mov(eax, FACTORY->true_value()); |
| 5207 __ bind(&done); | 5223 __ bind(&done); |
| 5208 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 5224 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| 5209 } | 5225 } |
| 5210 } | 5226 } |
| 5211 | 5227 |
| 5212 | 5228 |
| 5213 Register InstanceofStub::left() { return eax; } | 5229 Register InstanceofStub::left() { return eax; } |
| 5214 | 5230 |
| 5215 | 5231 |
| 5216 Register InstanceofStub::right() { return edx; } | 5232 Register InstanceofStub::right() { return edx; } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 5231 } | 5247 } |
| 5232 | 5248 |
| 5233 | 5249 |
| 5234 // Unfortunately you have to run without snapshots to see most of these | 5250 // Unfortunately you have to run without snapshots to see most of these |
| 5235 // names in the profile since most compare stubs end up in the snapshot. | 5251 // names in the profile since most compare stubs end up in the snapshot. |
| 5236 const char* CompareStub::GetName() { | 5252 const char* CompareStub::GetName() { |
| 5237 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); | 5253 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); |
| 5238 | 5254 |
| 5239 if (name_ != NULL) return name_; | 5255 if (name_ != NULL) return name_; |
| 5240 const int kMaxNameLength = 100; | 5256 const int kMaxNameLength = 100; |
| 5241 name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); | 5257 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( |
| 5258 kMaxNameLength); |
| 5242 if (name_ == NULL) return "OOM"; | 5259 if (name_ == NULL) return "OOM"; |
| 5243 | 5260 |
| 5244 const char* cc_name; | 5261 const char* cc_name; |
| 5245 switch (cc_) { | 5262 switch (cc_) { |
| 5246 case less: cc_name = "LT"; break; | 5263 case less: cc_name = "LT"; break; |
| 5247 case greater: cc_name = "GT"; break; | 5264 case greater: cc_name = "GT"; break; |
| 5248 case less_equal: cc_name = "LE"; break; | 5265 case less_equal: cc_name = "LE"; break; |
| 5249 case greater_equal: cc_name = "GE"; break; | 5266 case greater_equal: cc_name = "GE"; break; |
| 5250 case equal: cc_name = "EQ"; break; | 5267 case equal: cc_name = "EQ"; break; |
| 5251 case not_equal: cc_name = "NE"; break; | 5268 case not_equal: cc_name = "NE"; break; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5324 // Handle non-flat strings. | 5341 // Handle non-flat strings. |
| 5325 __ test(result_, Immediate(kIsConsStringMask)); | 5342 __ test(result_, Immediate(kIsConsStringMask)); |
| 5326 __ j(zero, &call_runtime_); | 5343 __ j(zero, &call_runtime_); |
| 5327 | 5344 |
| 5328 // ConsString. | 5345 // ConsString. |
| 5329 // Check whether the right hand side is the empty string (i.e. if | 5346 // Check whether the right hand side is the empty string (i.e. if |
| 5330 // this is really a flat string in a cons string). If that is not | 5347 // this is really a flat string in a cons string). If that is not |
| 5331 // the case we would rather go to the runtime system now to flatten | 5348 // the case we would rather go to the runtime system now to flatten |
| 5332 // the string. | 5349 // the string. |
| 5333 __ cmp(FieldOperand(object_, ConsString::kSecondOffset), | 5350 __ cmp(FieldOperand(object_, ConsString::kSecondOffset), |
| 5334 Immediate(Factory::empty_string())); | 5351 Immediate(FACTORY->empty_string())); |
| 5335 __ j(not_equal, &call_runtime_); | 5352 __ j(not_equal, &call_runtime_); |
| 5336 // Get the first of the two strings and load its instance type. | 5353 // Get the first of the two strings and load its instance type. |
| 5337 __ mov(object_, FieldOperand(object_, ConsString::kFirstOffset)); | 5354 __ mov(object_, FieldOperand(object_, ConsString::kFirstOffset)); |
| 5338 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); | 5355 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); |
| 5339 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); | 5356 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); |
| 5340 // If the first cons component is also non-flat, then go to runtime. | 5357 // If the first cons component is also non-flat, then go to runtime. |
| 5341 STATIC_ASSERT(kSeqStringTag == 0); | 5358 STATIC_ASSERT(kSeqStringTag == 0); |
| 5342 __ test(result_, Immediate(kStringRepresentationMask)); | 5359 __ test(result_, Immediate(kStringRepresentationMask)); |
| 5343 __ j(not_zero, &call_runtime_); | 5360 __ j(not_zero, &call_runtime_); |
| 5344 | 5361 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 5369 } | 5386 } |
| 5370 | 5387 |
| 5371 | 5388 |
| 5372 void StringCharCodeAtGenerator::GenerateSlow( | 5389 void StringCharCodeAtGenerator::GenerateSlow( |
| 5373 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { | 5390 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
| 5374 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); | 5391 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); |
| 5375 | 5392 |
| 5376 // Index is not a smi. | 5393 // Index is not a smi. |
| 5377 __ bind(&index_not_smi_); | 5394 __ bind(&index_not_smi_); |
| 5378 // If index is a heap number, try converting it to an integer. | 5395 // If index is a heap number, try converting it to an integer. |
| 5379 __ CheckMap(index_, Factory::heap_number_map(), index_not_number_, true); | 5396 __ CheckMap(index_, FACTORY->heap_number_map(), index_not_number_, true); |
| 5380 call_helper.BeforeCall(masm); | 5397 call_helper.BeforeCall(masm); |
| 5381 __ push(object_); | 5398 __ push(object_); |
| 5382 __ push(index_); | 5399 __ push(index_); |
| 5383 __ push(index_); // Consumed by runtime conversion function. | 5400 __ push(index_); // Consumed by runtime conversion function. |
| 5384 if (index_flags_ == STRING_INDEX_IS_NUMBER) { | 5401 if (index_flags_ == STRING_INDEX_IS_NUMBER) { |
| 5385 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); | 5402 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); |
| 5386 } else { | 5403 } else { |
| 5387 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); | 5404 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); |
| 5388 // NumberToSmi discards numbers that are not exact integers. | 5405 // NumberToSmi discards numbers that are not exact integers. |
| 5389 __ CallRuntime(Runtime::kNumberToSmi, 1); | 5406 __ CallRuntime(Runtime::kNumberToSmi, 1); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5430 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { | 5447 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { |
| 5431 // Fast case of Heap::LookupSingleCharacterStringFromCode. | 5448 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
| 5432 STATIC_ASSERT(kSmiTag == 0); | 5449 STATIC_ASSERT(kSmiTag == 0); |
| 5433 STATIC_ASSERT(kSmiShiftSize == 0); | 5450 STATIC_ASSERT(kSmiShiftSize == 0); |
| 5434 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); | 5451 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
| 5435 __ test(code_, | 5452 __ test(code_, |
| 5436 Immediate(kSmiTagMask | | 5453 Immediate(kSmiTagMask | |
| 5437 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); | 5454 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
| 5438 __ j(not_zero, &slow_case_, not_taken); | 5455 __ j(not_zero, &slow_case_, not_taken); |
| 5439 | 5456 |
| 5440 __ Set(result_, Immediate(Factory::single_character_string_cache())); | 5457 __ Set(result_, Immediate(FACTORY->single_character_string_cache())); |
| 5441 STATIC_ASSERT(kSmiTag == 0); | 5458 STATIC_ASSERT(kSmiTag == 0); |
| 5442 STATIC_ASSERT(kSmiTagSize == 1); | 5459 STATIC_ASSERT(kSmiTagSize == 1); |
| 5443 STATIC_ASSERT(kSmiShiftSize == 0); | 5460 STATIC_ASSERT(kSmiShiftSize == 0); |
| 5444 // At this point code register contains smi tagged ascii char code. | 5461 // At this point code register contains smi tagged ascii char code. |
| 5445 __ mov(result_, FieldOperand(result_, | 5462 __ mov(result_, FieldOperand(result_, |
| 5446 code_, times_half_pointer_size, | 5463 code_, times_half_pointer_size, |
| 5447 FixedArray::kHeaderSize)); | 5464 FixedArray::kHeaderSize)); |
| 5448 __ cmp(result_, Factory::undefined_value()); | 5465 __ cmp(result_, FACTORY->undefined_value()); |
| 5449 __ j(equal, &slow_case_, not_taken); | 5466 __ j(equal, &slow_case_, not_taken); |
| 5450 __ bind(&exit_); | 5467 __ bind(&exit_); |
| 5451 } | 5468 } |
| 5452 | 5469 |
| 5453 | 5470 |
| 5454 void StringCharFromCodeGenerator::GenerateSlow( | 5471 void StringCharFromCodeGenerator::GenerateSlow( |
| 5455 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { | 5472 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
| 5456 __ Abort("Unexpected fallthrough to CharFromCode slow case"); | 5473 __ Abort("Unexpected fallthrough to CharFromCode slow case"); |
| 5457 | 5474 |
| 5458 __ bind(&slow_case_); | 5475 __ bind(&slow_case_); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5524 // Both arguments are strings. | 5541 // Both arguments are strings. |
| 5525 // eax: first string | 5542 // eax: first string |
| 5526 // edx: second string | 5543 // edx: second string |
| 5527 // Check if either of the strings are empty. In that case return the other. | 5544 // Check if either of the strings are empty. In that case return the other. |
| 5528 NearLabel second_not_zero_length, both_not_zero_length; | 5545 NearLabel second_not_zero_length, both_not_zero_length; |
| 5529 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); | 5546 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); |
| 5530 STATIC_ASSERT(kSmiTag == 0); | 5547 STATIC_ASSERT(kSmiTag == 0); |
| 5531 __ test(ecx, Operand(ecx)); | 5548 __ test(ecx, Operand(ecx)); |
| 5532 __ j(not_zero, &second_not_zero_length); | 5549 __ j(not_zero, &second_not_zero_length); |
| 5533 // Second string is empty, result is first string which is already in eax. | 5550 // Second string is empty, result is first string which is already in eax. |
| 5534 __ IncrementCounter(&Counters::string_add_native, 1); | 5551 __ IncrementCounter(COUNTERS->string_add_native(), 1); |
| 5535 __ ret(2 * kPointerSize); | 5552 __ ret(2 * kPointerSize); |
| 5536 __ bind(&second_not_zero_length); | 5553 __ bind(&second_not_zero_length); |
| 5537 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); | 5554 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); |
| 5538 STATIC_ASSERT(kSmiTag == 0); | 5555 STATIC_ASSERT(kSmiTag == 0); |
| 5539 __ test(ebx, Operand(ebx)); | 5556 __ test(ebx, Operand(ebx)); |
| 5540 __ j(not_zero, &both_not_zero_length); | 5557 __ j(not_zero, &both_not_zero_length); |
| 5541 // First string is empty, result is second string which is in edx. | 5558 // First string is empty, result is second string which is in edx. |
| 5542 __ mov(eax, edx); | 5559 __ mov(eax, edx); |
| 5543 __ IncrementCounter(&Counters::string_add_native, 1); | 5560 __ IncrementCounter(COUNTERS->string_add_native(), 1); |
| 5544 __ ret(2 * kPointerSize); | 5561 __ ret(2 * kPointerSize); |
| 5545 | 5562 |
| 5546 // Both strings are non-empty. | 5563 // Both strings are non-empty. |
| 5547 // eax: first string | 5564 // eax: first string |
| 5548 // ebx: length of first string as a smi | 5565 // ebx: length of first string as a smi |
| 5549 // ecx: length of second string as a smi | 5566 // ecx: length of second string as a smi |
| 5550 // edx: second string | 5567 // edx: second string |
| 5551 // Look at the length of the result of adding the two strings. | 5568 // Look at the length of the result of adding the two strings. |
| 5552 Label string_add_flat_result, longer_than_two; | 5569 Label string_add_flat_result, longer_than_two; |
| 5553 __ bind(&both_not_zero_length); | 5570 __ bind(&both_not_zero_length); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 5567 // Get the two characters forming the new string. | 5584 // Get the two characters forming the new string. |
| 5568 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); | 5585 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); |
| 5569 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); | 5586 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); |
| 5570 | 5587 |
| 5571 // Try to lookup two character string in symbol table. If it is not found | 5588 // Try to lookup two character string in symbol table. If it is not found |
| 5572 // just allocate a new one. | 5589 // just allocate a new one. |
| 5573 Label make_two_character_string, make_two_character_string_no_reload; | 5590 Label make_two_character_string, make_two_character_string_no_reload; |
| 5574 StringHelper::GenerateTwoCharacterSymbolTableProbe( | 5591 StringHelper::GenerateTwoCharacterSymbolTableProbe( |
| 5575 masm, ebx, ecx, eax, edx, edi, | 5592 masm, ebx, ecx, eax, edx, edi, |
| 5576 &make_two_character_string_no_reload, &make_two_character_string); | 5593 &make_two_character_string_no_reload, &make_two_character_string); |
| 5577 __ IncrementCounter(&Counters::string_add_native, 1); | 5594 __ IncrementCounter(COUNTERS->string_add_native(), 1); |
| 5578 __ ret(2 * kPointerSize); | 5595 __ ret(2 * kPointerSize); |
| 5579 | 5596 |
| 5580 // Allocate a two character string. | 5597 // Allocate a two character string. |
| 5581 __ bind(&make_two_character_string); | 5598 __ bind(&make_two_character_string); |
| 5582 // Reload the arguments. | 5599 // Reload the arguments. |
| 5583 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | 5600 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. |
| 5584 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | 5601 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. |
| 5585 // Get the two characters forming the new string. | 5602 // Get the two characters forming the new string. |
| 5586 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); | 5603 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); |
| 5587 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); | 5604 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); |
| 5588 __ bind(&make_two_character_string_no_reload); | 5605 __ bind(&make_two_character_string_no_reload); |
| 5589 __ IncrementCounter(&Counters::string_add_make_two_char, 1); | 5606 __ IncrementCounter(COUNTERS->string_add_make_two_char(), 1); |
| 5590 __ AllocateAsciiString(eax, // Result. | 5607 __ AllocateAsciiString(eax, // Result. |
| 5591 2, // Length. | 5608 2, // Length. |
| 5592 edi, // Scratch 1. | 5609 edi, // Scratch 1. |
| 5593 edx, // Scratch 2. | 5610 edx, // Scratch 2. |
| 5594 &string_add_runtime); | 5611 &string_add_runtime); |
| 5595 // Pack both characters in ebx. | 5612 // Pack both characters in ebx. |
| 5596 __ shl(ecx, kBitsPerByte); | 5613 __ shl(ecx, kBitsPerByte); |
| 5597 __ or_(ebx, Operand(ecx)); | 5614 __ or_(ebx, Operand(ecx)); |
| 5598 // Set the characters in the new string. | 5615 // Set the characters in the new string. |
| 5599 __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx); | 5616 __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx); |
| 5600 __ IncrementCounter(&Counters::string_add_native, 1); | 5617 __ IncrementCounter(COUNTERS->string_add_native(), 1); |
| 5601 __ ret(2 * kPointerSize); | 5618 __ ret(2 * kPointerSize); |
| 5602 | 5619 |
| 5603 __ bind(&longer_than_two); | 5620 __ bind(&longer_than_two); |
| 5604 // Check if resulting string will be flat. | 5621 // Check if resulting string will be flat. |
| 5605 __ cmp(Operand(ebx), Immediate(Smi::FromInt(String::kMinNonFlatLength))); | 5622 __ cmp(Operand(ebx), Immediate(Smi::FromInt(String::kMinNonFlatLength))); |
| 5606 __ j(below, &string_add_flat_result); | 5623 __ j(below, &string_add_flat_result); |
| 5607 | 5624 |
| 5608 // If result is not supposed to be flat allocate a cons string object. If both | 5625 // If result is not supposed to be flat allocate a cons string object. If both |
| 5609 // strings are ascii the result is an ascii cons string. | 5626 // strings are ascii the result is an ascii cons string. |
| 5610 Label non_ascii, allocated, ascii_data; | 5627 Label non_ascii, allocated, ascii_data; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 5621 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); | 5638 __ AllocateAsciiConsString(ecx, edi, no_reg, &string_add_runtime); |
| 5622 __ bind(&allocated); | 5639 __ bind(&allocated); |
| 5623 // Fill the fields of the cons string. | 5640 // Fill the fields of the cons string. |
| 5624 if (FLAG_debug_code) __ AbortIfNotSmi(ebx); | 5641 if (FLAG_debug_code) __ AbortIfNotSmi(ebx); |
| 5625 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); | 5642 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); |
| 5626 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), | 5643 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), |
| 5627 Immediate(String::kEmptyHashField)); | 5644 Immediate(String::kEmptyHashField)); |
| 5628 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); | 5645 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); |
| 5629 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); | 5646 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); |
| 5630 __ mov(eax, ecx); | 5647 __ mov(eax, ecx); |
| 5631 __ IncrementCounter(&Counters::string_add_native, 1); | 5648 __ IncrementCounter(COUNTERS->string_add_native(), 1); |
| 5632 __ ret(2 * kPointerSize); | 5649 __ ret(2 * kPointerSize); |
| 5633 __ bind(&non_ascii); | 5650 __ bind(&non_ascii); |
| 5634 // At least one of the strings is two-byte. Check whether it happens | 5651 // At least one of the strings is two-byte. Check whether it happens |
| 5635 // to contain only ascii characters. | 5652 // to contain only ascii characters. |
| 5636 // ecx: first instance type AND second instance type. | 5653 // ecx: first instance type AND second instance type. |
| 5637 // edi: second instance type. | 5654 // edi: second instance type. |
| 5638 __ test(ecx, Immediate(kAsciiDataHintMask)); | 5655 __ test(ecx, Immediate(kAsciiDataHintMask)); |
| 5639 __ j(not_zero, &ascii_data); | 5656 __ j(not_zero, &ascii_data); |
| 5640 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 5657 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 5641 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 5658 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5698 // Load second argument and locate first character. | 5715 // Load second argument and locate first character. |
| 5699 __ mov(edx, Operand(esp, 1 * kPointerSize)); | 5716 __ mov(edx, Operand(esp, 1 * kPointerSize)); |
| 5700 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 5717 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
| 5701 __ SmiUntag(edi); | 5718 __ SmiUntag(edi); |
| 5702 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 5719 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 5703 // eax: result string | 5720 // eax: result string |
| 5704 // ecx: next character of result | 5721 // ecx: next character of result |
| 5705 // edx: first char of second argument | 5722 // edx: first char of second argument |
| 5706 // edi: length of second argument | 5723 // edi: length of second argument |
| 5707 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 5724 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
| 5708 __ IncrementCounter(&Counters::string_add_native, 1); | 5725 __ IncrementCounter(COUNTERS->string_add_native(), 1); |
| 5709 __ ret(2 * kPointerSize); | 5726 __ ret(2 * kPointerSize); |
| 5710 | 5727 |
| 5711 // Handle creating a flat two byte result. | 5728 // Handle creating a flat two byte result. |
| 5712 // eax: first string - known to be two byte | 5729 // eax: first string - known to be two byte |
| 5713 // ebx: length of resulting flat string as a smi | 5730 // ebx: length of resulting flat string as a smi |
| 5714 // edx: second string | 5731 // edx: second string |
| 5715 __ bind(&non_ascii_string_add_flat_result); | 5732 __ bind(&non_ascii_string_add_flat_result); |
| 5716 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 5733 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 5717 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); | 5734 __ test_b(FieldOperand(ecx, Map::kInstanceTypeOffset), kAsciiStringTag); |
| 5718 __ j(not_zero, &string_add_runtime); | 5735 __ j(not_zero, &string_add_runtime); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 5739 // Load second argument and locate first character. | 5756 // Load second argument and locate first character. |
| 5740 __ mov(edx, Operand(esp, 1 * kPointerSize)); | 5757 __ mov(edx, Operand(esp, 1 * kPointerSize)); |
| 5741 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 5758 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
| 5742 __ SmiUntag(edi); | 5759 __ SmiUntag(edi); |
| 5743 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 5760 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 5744 // eax: result string | 5761 // eax: result string |
| 5745 // ecx: next character of result | 5762 // ecx: next character of result |
| 5746 // edx: first char of second argument | 5763 // edx: first char of second argument |
| 5747 // edi: length of second argument | 5764 // edi: length of second argument |
| 5748 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 5765 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
| 5749 __ IncrementCounter(&Counters::string_add_native, 1); | 5766 __ IncrementCounter(COUNTERS->string_add_native(), 1); |
| 5750 __ ret(2 * kPointerSize); | 5767 __ ret(2 * kPointerSize); |
| 5751 | 5768 |
| 5752 // Just jump to runtime to add the two strings. | 5769 // Just jump to runtime to add the two strings. |
| 5753 __ bind(&string_add_runtime); | 5770 __ bind(&string_add_runtime); |
| 5754 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 5771 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 5755 | 5772 |
| 5756 if (call_builtin.is_linked()) { | 5773 if (call_builtin.is_linked()) { |
| 5757 __ bind(&call_builtin); | 5774 __ bind(&call_builtin); |
| 5758 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | 5775 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); |
| 5759 } | 5776 } |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5964 // Load the entry from the symbol table. | 5981 // Load the entry from the symbol table. |
| 5965 Register candidate = scratch; // Scratch register contains candidate. | 5982 Register candidate = scratch; // Scratch register contains candidate. |
| 5966 STATIC_ASSERT(SymbolTable::kEntrySize == 1); | 5983 STATIC_ASSERT(SymbolTable::kEntrySize == 1); |
| 5967 __ mov(candidate, | 5984 __ mov(candidate, |
| 5968 FieldOperand(symbol_table, | 5985 FieldOperand(symbol_table, |
| 5969 scratch, | 5986 scratch, |
| 5970 times_pointer_size, | 5987 times_pointer_size, |
| 5971 SymbolTable::kElementsStartOffset)); | 5988 SymbolTable::kElementsStartOffset)); |
| 5972 | 5989 |
| 5973 // If entry is undefined no string with this hash can be found. | 5990 // If entry is undefined no string with this hash can be found. |
| 5974 __ cmp(candidate, Factory::undefined_value()); | 5991 __ cmp(candidate, FACTORY->undefined_value()); |
| 5975 __ j(equal, not_found); | 5992 __ j(equal, not_found); |
| 5976 __ cmp(candidate, Factory::null_value()); | 5993 __ cmp(candidate, FACTORY->null_value()); |
| 5977 __ j(equal, &next_probe[i]); | 5994 __ j(equal, &next_probe[i]); |
| 5978 | 5995 |
| 5979 // If length is not 2 the string is not a candidate. | 5996 // If length is not 2 the string is not a candidate. |
| 5980 __ cmp(FieldOperand(candidate, String::kLengthOffset), | 5997 __ cmp(FieldOperand(candidate, String::kLengthOffset), |
| 5981 Immediate(Smi::FromInt(2))); | 5998 Immediate(Smi::FromInt(2))); |
| 5982 __ j(not_equal, &next_probe[i]); | 5999 __ j(not_equal, &next_probe[i]); |
| 5983 | 6000 |
| 5984 // As we are out of registers save the mask on the stack and use that | 6001 // As we are out of registers save the mask on the stack and use that |
| 5985 // register as a temporary. | 6002 // register as a temporary. |
| 5986 __ push(mask); | 6003 __ push(mask); |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6163 __ SmiUntag(ebx); | 6180 __ SmiUntag(ebx); |
| 6164 __ add(esi, Operand(ebx)); | 6181 __ add(esi, Operand(ebx)); |
| 6165 | 6182 |
| 6166 // eax: result string | 6183 // eax: result string |
| 6167 // ecx: result length | 6184 // ecx: result length |
| 6168 // edx: original value of esi | 6185 // edx: original value of esi |
| 6169 // edi: first character of result | 6186 // edi: first character of result |
| 6170 // esi: character of sub string start | 6187 // esi: character of sub string start |
| 6171 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); | 6188 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); |
| 6172 __ mov(esi, edx); // Restore esi. | 6189 __ mov(esi, edx); // Restore esi. |
| 6173 __ IncrementCounter(&Counters::sub_string_native, 1); | 6190 __ IncrementCounter(COUNTERS->sub_string_native(), 1); |
| 6174 __ ret(3 * kPointerSize); | 6191 __ ret(3 * kPointerSize); |
| 6175 | 6192 |
| 6176 __ bind(&non_ascii_flat); | 6193 __ bind(&non_ascii_flat); |
| 6177 // eax: string | 6194 // eax: string |
| 6178 // ebx: instance type & kStringRepresentationMask | kStringEncodingMask | 6195 // ebx: instance type & kStringRepresentationMask | kStringEncodingMask |
| 6179 // ecx: result string length | 6196 // ecx: result string length |
| 6180 // Check for flat two byte string | 6197 // Check for flat two byte string |
| 6181 __ cmp(ebx, kSeqStringTag | kTwoByteStringTag); | 6198 __ cmp(ebx, kSeqStringTag | kTwoByteStringTag); |
| 6182 __ j(not_equal, &runtime); | 6199 __ j(not_equal, &runtime); |
| 6183 | 6200 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 6204 | 6221 |
| 6205 // eax: result string | 6222 // eax: result string |
| 6206 // ecx: result length | 6223 // ecx: result length |
| 6207 // edx: original value of esi | 6224 // edx: original value of esi |
| 6208 // edi: first character of result | 6225 // edi: first character of result |
| 6209 // esi: character of sub string start | 6226 // esi: character of sub string start |
| 6210 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); | 6227 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); |
| 6211 __ mov(esi, edx); // Restore esi. | 6228 __ mov(esi, edx); // Restore esi. |
| 6212 | 6229 |
| 6213 __ bind(&return_eax); | 6230 __ bind(&return_eax); |
| 6214 __ IncrementCounter(&Counters::sub_string_native, 1); | 6231 __ IncrementCounter(COUNTERS->sub_string_native(), 1); |
| 6215 __ ret(3 * kPointerSize); | 6232 __ ret(3 * kPointerSize); |
| 6216 | 6233 |
| 6217 // Just jump to runtime to create the sub string. | 6234 // Just jump to runtime to create the sub string. |
| 6218 __ bind(&runtime); | 6235 __ bind(&runtime); |
| 6219 __ TailCallRuntime(Runtime::kSubString, 3, 1); | 6236 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
| 6220 } | 6237 } |
| 6221 | 6238 |
| 6222 | 6239 |
| 6223 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, | 6240 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, |
| 6224 Register left, | 6241 Register left, |
| 6225 Register right, | 6242 Register right, |
| 6226 Register scratch1, | 6243 Register scratch1, |
| 6227 Register scratch2, | 6244 Register scratch2, |
| 6228 Register scratch3) { | 6245 Register scratch3) { |
| 6229 Label result_not_equal; | 6246 Label result_not_equal; |
| 6230 Label result_greater; | 6247 Label result_greater; |
| 6231 Label compare_lengths; | 6248 Label compare_lengths; |
| 6232 | 6249 |
| 6233 __ IncrementCounter(&Counters::string_compare_native, 1); | 6250 __ IncrementCounter(COUNTERS->string_compare_native(), 1); |
| 6234 | 6251 |
| 6235 // Find minimum length. | 6252 // Find minimum length. |
| 6236 NearLabel left_shorter; | 6253 NearLabel left_shorter; |
| 6237 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); | 6254 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); |
| 6238 __ mov(scratch3, scratch1); | 6255 __ mov(scratch3, scratch1); |
| 6239 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); | 6256 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); |
| 6240 | 6257 |
| 6241 Register length_delta = scratch3; | 6258 Register length_delta = scratch3; |
| 6242 | 6259 |
| 6243 __ j(less_equal, &left_shorter); | 6260 __ j(less_equal, &left_shorter); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6314 | 6331 |
| 6315 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left | 6332 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left |
| 6316 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right | 6333 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right |
| 6317 | 6334 |
| 6318 NearLabel not_same; | 6335 NearLabel not_same; |
| 6319 __ cmp(edx, Operand(eax)); | 6336 __ cmp(edx, Operand(eax)); |
| 6320 __ j(not_equal, ¬_same); | 6337 __ j(not_equal, ¬_same); |
| 6321 STATIC_ASSERT(EQUAL == 0); | 6338 STATIC_ASSERT(EQUAL == 0); |
| 6322 STATIC_ASSERT(kSmiTag == 0); | 6339 STATIC_ASSERT(kSmiTag == 0); |
| 6323 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); | 6340 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); |
| 6324 __ IncrementCounter(&Counters::string_compare_native, 1); | 6341 __ IncrementCounter(COUNTERS->string_compare_native(), 1); |
| 6325 __ ret(2 * kPointerSize); | 6342 __ ret(2 * kPointerSize); |
| 6326 | 6343 |
| 6327 __ bind(¬_same); | 6344 __ bind(¬_same); |
| 6328 | 6345 |
| 6329 // Check that both objects are sequential ascii strings. | 6346 // Check that both objects are sequential ascii strings. |
| 6330 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); | 6347 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); |
| 6331 | 6348 |
| 6332 // Compare flat ascii strings. | 6349 // Compare flat ascii strings. |
| 6333 // Drop arguments from the stack. | 6350 // Drop arguments from the stack. |
| 6334 __ pop(ecx); | 6351 __ pop(ecx); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6381 __ test(ecx, Immediate(kSmiTagMask)); | 6398 __ test(ecx, Immediate(kSmiTagMask)); |
| 6382 __ j(zero, &generic_stub, not_taken); | 6399 __ j(zero, &generic_stub, not_taken); |
| 6383 | 6400 |
| 6384 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); | 6401 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); |
| 6385 __ j(not_equal, &miss, not_taken); | 6402 __ j(not_equal, &miss, not_taken); |
| 6386 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); | 6403 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); |
| 6387 __ j(not_equal, &miss, not_taken); | 6404 __ j(not_equal, &miss, not_taken); |
| 6388 | 6405 |
| 6389 // Inlining the double comparison and falling back to the general compare | 6406 // Inlining the double comparison and falling back to the general compare |
| 6390 // stub if NaN is involved or SS2 or CMOV is unsupported. | 6407 // stub if NaN is involved or SS2 or CMOV is unsupported. |
| 6391 if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { | 6408 CpuFeatures* cpu_features = Isolate::Current()->cpu_features(); |
| 6409 if (cpu_features->IsSupported(SSE2) && cpu_features->IsSupported(CMOV)) { |
| 6392 CpuFeatures::Scope scope1(SSE2); | 6410 CpuFeatures::Scope scope1(SSE2); |
| 6393 CpuFeatures::Scope scope2(CMOV); | 6411 CpuFeatures::Scope scope2(CMOV); |
| 6394 | 6412 |
| 6395 // Load left and right operand | 6413 // Load left and right operand |
| 6396 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); | 6414 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); |
| 6397 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); | 6415 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 6398 | 6416 |
| 6399 // Compare operands | 6417 // Compare operands |
| 6400 __ ucomisd(xmm0, xmm1); | 6418 __ ucomisd(xmm0, xmm1); |
| 6401 | 6419 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6471 __ push(ecx); | 6489 __ push(ecx); |
| 6472 | 6490 |
| 6473 // Do a tail call to the rewritten stub. | 6491 // Do a tail call to the rewritten stub. |
| 6474 __ jmp(Operand(edi)); | 6492 __ jmp(Operand(edi)); |
| 6475 } | 6493 } |
| 6476 | 6494 |
| 6477 | 6495 |
| 6478 void RecordWriteStub::Generate(MacroAssembler* masm) { | 6496 void RecordWriteStub::Generate(MacroAssembler* masm) { |
| 6479 NearLabel skip_incremental_part; | 6497 NearLabel skip_incremental_part; |
| 6480 __ jmp(&skip_incremental_part); | 6498 __ jmp(&skip_incremental_part); |
| 6481 if (!IncrementalMarking::IsStopped()) { | 6499 |
| 6500 // TODO(gc) ISOLATES MERGE |
| 6501 // TODO(gc) possible bug, figure out what happens if GC is triggered |
| 6502 // (incremental marking starts) during allocation of code object for this |
| 6503 // stub. Looks like this stub will not be patched. |
| 6504 if (!HEAP->incremental_marking()->IsStopped()) { |
| 6482 ASSERT(masm->get_opcode(-2) == kSkipIncrementalPartInstruction); | 6505 ASSERT(masm->get_opcode(-2) == kSkipIncrementalPartInstruction); |
| 6483 masm->set_opcode(-2, kTwoByteNopInstruction); | 6506 masm->set_opcode(-2, kTwoByteNopInstruction); |
| 6484 } | 6507 } |
| 6485 | 6508 |
| 6486 // If we are also emitting the remembered set code in this stub then we have | 6509 // If we are also emitting the remembered set code in this stub then we have |
| 6487 // the object we are writing into in the 'object' register and the slot in | 6510 // the object we are writing into in the 'object' register and the slot in |
| 6488 // the 'address' register. We insert a primitive test here to ensure that | 6511 // the 'address' register. We insert a primitive test here to ensure that |
| 6489 // this is the case. Otherwise the 'address' register is merely a scratch | 6512 // this is the case. Otherwise the 'address' register is merely a scratch |
| 6490 // register. | 6513 // register. |
| 6491 if (FLAG_debug_code && emit_remembered_set_ == EMIT_REMEMBERED_SET) { | 6514 if (FLAG_debug_code && emit_remembered_set_ == EMIT_REMEMBERED_SET) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 6509 } | 6532 } |
| 6510 __ ret(0); | 6533 __ ret(0); |
| 6511 } | 6534 } |
| 6512 | 6535 |
| 6513 | 6536 |
| 6514 #undef __ | 6537 #undef __ |
| 6515 | 6538 |
| 6516 } } // namespace v8::internal | 6539 } } // namespace v8::internal |
| 6517 | 6540 |
| 6518 #endif // V8_TARGET_ARCH_IA32 | 6541 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |