| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #if V8_TARGET_ARCH_X64 | 7 #if V8_TARGET_ARCH_X64 |
| 8 | 8 |
| 9 #include "src/bootstrapper.h" | 9 #include "src/bootstrapper.h" |
| 10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
| 11 #include "src/regexp-macro-assembler.h" | 11 #include "src/regexp-macro-assembler.h" |
| 12 #include "src/runtime.h" | 12 #include "src/runtime.h" |
| 13 #include "src/stub-cache.h" | 13 #include "src/stub-cache.h" |
| 14 | 14 |
| 15 namespace v8 { | 15 namespace v8 { |
| 16 namespace internal { | 16 namespace internal { |
| 17 | 17 |
| 18 | 18 |
| 19 void FastNewClosureStub::InitializeInterfaceDescriptor( | 19 void FastNewClosureStub::InitializeInterfaceDescriptor( |
| 20 CodeStubInterfaceDescriptor* descriptor) { | 20 CodeStubInterfaceDescriptor* descriptor) { |
| 21 Register registers[] = { rsi, rbx }; | 21 Register registers[] = { rsi, rbx }; |
| 22 descriptor->Initialize( | 22 descriptor->Initialize( |
| 23 ARRAY_SIZE(registers), registers, | 23 MajorKey(), ARRAY_SIZE(registers), registers, |
| 24 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry); | 24 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry); |
| 25 } | 25 } |
| 26 | 26 |
| 27 | 27 |
| 28 void FastNewContextStub::InitializeInterfaceDescriptor( | 28 void FastNewContextStub::InitializeInterfaceDescriptor( |
| 29 CodeStubInterfaceDescriptor* descriptor) { | 29 CodeStubInterfaceDescriptor* descriptor) { |
| 30 Register registers[] = { rsi, rdi }; | 30 Register registers[] = { rsi, rdi }; |
| 31 descriptor->Initialize(ARRAY_SIZE(registers), registers); | 31 descriptor->Initialize(MajorKey(), ARRAY_SIZE(registers), registers); |
| 32 } | 32 } |
| 33 | 33 |
| 34 | 34 |
| 35 void ToNumberStub::InitializeInterfaceDescriptor( | 35 void ToNumberStub::InitializeInterfaceDescriptor( |
| 36 CodeStubInterfaceDescriptor* descriptor) { | 36 CodeStubInterfaceDescriptor* descriptor) { |
| 37 Register registers[] = { rsi, rax }; | 37 Register registers[] = { rsi, rax }; |
| 38 descriptor->Initialize(ARRAY_SIZE(registers), registers); | 38 descriptor->Initialize(MajorKey(), ARRAY_SIZE(registers), registers); |
| 39 } | 39 } |
| 40 | 40 |
| 41 | 41 |
| 42 void NumberToStringStub::InitializeInterfaceDescriptor( | 42 void NumberToStringStub::InitializeInterfaceDescriptor( |
| 43 CodeStubInterfaceDescriptor* descriptor) { | 43 CodeStubInterfaceDescriptor* descriptor) { |
| 44 Register registers[] = { rsi, rax }; | 44 Register registers[] = { rsi, rax }; |
| 45 descriptor->Initialize( | 45 descriptor->Initialize( |
| 46 ARRAY_SIZE(registers), registers, | 46 MajorKey(), ARRAY_SIZE(registers), registers, |
| 47 Runtime::FunctionForId(Runtime::kNumberToStringRT)->entry); | 47 Runtime::FunctionForId(Runtime::kNumberToStringRT)->entry); |
| 48 } | 48 } |
| 49 | 49 |
| 50 | 50 |
| 51 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor( | 51 void FastCloneShallowArrayStub::InitializeInterfaceDescriptor( |
| 52 CodeStubInterfaceDescriptor* descriptor) { | 52 CodeStubInterfaceDescriptor* descriptor) { |
| 53 Register registers[] = { rsi, rax, rbx, rcx }; | 53 Register registers[] = { rsi, rax, rbx, rcx }; |
| 54 Representation representations[] = { | 54 Representation representations[] = { |
| 55 Representation::Tagged(), | 55 Representation::Tagged(), |
| 56 Representation::Tagged(), | 56 Representation::Tagged(), |
| 57 Representation::Smi(), | 57 Representation::Smi(), |
| 58 Representation::Tagged() }; | 58 Representation::Tagged() }; |
| 59 | 59 |
| 60 descriptor->Initialize( | 60 descriptor->Initialize( |
| 61 ARRAY_SIZE(registers), registers, | 61 MajorKey(), ARRAY_SIZE(registers), registers, |
| 62 Runtime::FunctionForId( | 62 Runtime::FunctionForId(Runtime::kCreateArrayLiteralStubBailout)->entry, |
| 63 Runtime::kCreateArrayLiteralStubBailout)->entry, | |
| 64 representations); | 63 representations); |
| 65 } | 64 } |
| 66 | 65 |
| 67 | 66 |
| 68 void FastCloneShallowObjectStub::InitializeInterfaceDescriptor( | 67 void FastCloneShallowObjectStub::InitializeInterfaceDescriptor( |
| 69 CodeStubInterfaceDescriptor* descriptor) { | 68 CodeStubInterfaceDescriptor* descriptor) { |
| 70 Register registers[] = { rsi, rax, rbx, rcx, rdx }; | 69 Register registers[] = { rsi, rax, rbx, rcx, rdx }; |
| 71 descriptor->Initialize( | 70 descriptor->Initialize( |
| 72 ARRAY_SIZE(registers), registers, | 71 MajorKey(), ARRAY_SIZE(registers), registers, |
| 73 Runtime::FunctionForId(Runtime::kCreateObjectLiteral)->entry); | 72 Runtime::FunctionForId(Runtime::kCreateObjectLiteral)->entry); |
| 74 } | 73 } |
| 75 | 74 |
| 76 | 75 |
| 77 void CreateAllocationSiteStub::InitializeInterfaceDescriptor( | 76 void CreateAllocationSiteStub::InitializeInterfaceDescriptor( |
| 78 CodeStubInterfaceDescriptor* descriptor) { | 77 CodeStubInterfaceDescriptor* descriptor) { |
| 79 Register registers[] = { rsi, rbx, rdx }; | 78 Register registers[] = { rsi, rbx, rdx }; |
| 80 descriptor->Initialize(ARRAY_SIZE(registers), registers); | 79 descriptor->Initialize(MajorKey(), ARRAY_SIZE(registers), registers); |
| 81 } | 80 } |
| 82 | 81 |
| 83 | 82 |
| 83 void InstanceofStub::InitializeInterfaceDescriptor( |
| 84 Isolate* isolate, |
| 85 CodeStubInterfaceDescriptor* descriptor) { |
| 86 Register registers[] = { rsi, left(), right() }; |
| 87 descriptor->Initialize(MajorKey(), ARRAY_SIZE(registers), registers); |
| 88 } |
| 89 |
| 90 |
| 91 void CallFunctionStub::InitializeInterfaceDescriptor( |
| 92 Isolate* isolate, |
| 93 CodeStubInterfaceDescriptor* descriptor) { |
| 94 Register registers[] = { rsi, rdi }; |
| 95 descriptor->Initialize(MajorKey(), ARRAY_SIZE(registers), registers); |
| 96 } |
| 97 |
| 98 |
| 99 void CallConstructStub::InitializeInterfaceDescriptor( |
| 100 Isolate* isolate, |
| 101 CodeStubInterfaceDescriptor* descriptor) { |
| 102 // rax : number of arguments |
| 103 // rbx : feedback vector |
| 104 // rdx : (only if rbx is not the megamorphic symbol) slot in feedback |
| 105 // vector (Smi) |
| 106 // rdi : constructor function |
| 107 // TODO(turbofan): So far we don't gather type feedback and hence skip the |
| 108 // slot parameter, but ArrayConstructStub needs the vector to be undefined. |
| 109 Register registers[] = { rsi, rax, rdi, rbx }; |
| 110 descriptor->Initialize(MajorKey(), ARRAY_SIZE(registers), registers); |
| 111 } |
| 112 |
| 113 |
| 84 void RegExpConstructResultStub::InitializeInterfaceDescriptor( | 114 void RegExpConstructResultStub::InitializeInterfaceDescriptor( |
| 85 CodeStubInterfaceDescriptor* descriptor) { | 115 CodeStubInterfaceDescriptor* descriptor) { |
| 86 Register registers[] = { rsi, rcx, rbx, rax }; | 116 Register registers[] = { rsi, rcx, rbx, rax }; |
| 87 descriptor->Initialize( | 117 descriptor->Initialize( |
| 88 ARRAY_SIZE(registers), registers, | 118 MajorKey(), ARRAY_SIZE(registers), registers, |
| 89 Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry); | 119 Runtime::FunctionForId(Runtime::kRegExpConstructResult)->entry); |
| 90 } | 120 } |
| 91 | 121 |
| 92 | 122 |
| 93 void TransitionElementsKindStub::InitializeInterfaceDescriptor( | 123 void TransitionElementsKindStub::InitializeInterfaceDescriptor( |
| 94 CodeStubInterfaceDescriptor* descriptor) { | 124 CodeStubInterfaceDescriptor* descriptor) { |
| 95 Register registers[] = { rsi, rax, rbx }; | 125 Register registers[] = { rsi, rax, rbx }; |
| 96 descriptor->Initialize( | 126 descriptor->Initialize( |
| 97 ARRAY_SIZE(registers), registers, | 127 MajorKey(), ARRAY_SIZE(registers), registers, |
| 98 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry); | 128 Runtime::FunctionForId(Runtime::kTransitionElementsKind)->entry); |
| 99 } | 129 } |
| 100 | 130 |
| 101 | 131 |
| 102 const Register InterfaceDescriptor::ContextRegister() { return rsi; } | 132 const Register InterfaceDescriptor::ContextRegister() { return rsi; } |
| 103 | 133 |
| 104 | 134 |
| 105 static void InitializeArrayConstructorDescriptor( | 135 static void InitializeArrayConstructorDescriptor( |
| 106 CodeStubInterfaceDescriptor* descriptor, | 136 CodeStub::Major major, CodeStubInterfaceDescriptor* descriptor, |
| 107 int constant_stack_parameter_count) { | 137 int constant_stack_parameter_count) { |
| 108 // register state | 138 // register state |
| 109 // rax -- number of arguments | 139 // rax -- number of arguments |
| 110 // rdi -- function | 140 // rdi -- function |
| 111 // rbx -- allocation site with elements kind | 141 // rbx -- allocation site with elements kind |
| 112 Address deopt_handler = Runtime::FunctionForId( | 142 Address deopt_handler = Runtime::FunctionForId( |
| 113 Runtime::kArrayConstructor)->entry; | 143 Runtime::kArrayConstructor)->entry; |
| 114 | 144 |
| 115 if (constant_stack_parameter_count == 0) { | 145 if (constant_stack_parameter_count == 0) { |
| 116 Register registers[] = { rsi, rdi, rbx }; | 146 Register registers[] = { rsi, rdi, rbx }; |
| 117 descriptor->Initialize(ARRAY_SIZE(registers), registers, | 147 descriptor->Initialize(major, ARRAY_SIZE(registers), registers, |
| 118 deopt_handler, | 148 deopt_handler, NULL, constant_stack_parameter_count, |
| 119 NULL, | |
| 120 constant_stack_parameter_count, | |
| 121 JS_FUNCTION_STUB_MODE); | 149 JS_FUNCTION_STUB_MODE); |
| 122 } else { | 150 } else { |
| 123 // stack param count needs (constructor pointer, and single argument) | 151 // stack param count needs (constructor pointer, and single argument) |
| 124 Register registers[] = { rsi, rdi, rbx, rax }; | 152 Register registers[] = { rsi, rdi, rbx, rax }; |
| 125 Representation representations[] = { | 153 Representation representations[] = { |
| 126 Representation::Tagged(), | 154 Representation::Tagged(), |
| 127 Representation::Tagged(), | 155 Representation::Tagged(), |
| 128 Representation::Tagged(), | 156 Representation::Tagged(), |
| 129 Representation::Integer32() }; | 157 Representation::Integer32() }; |
| 130 descriptor->Initialize(ARRAY_SIZE(registers), registers, | 158 descriptor->Initialize(major, ARRAY_SIZE(registers), registers, rax, |
| 131 rax, | 159 deopt_handler, representations, |
| 132 deopt_handler, | |
| 133 representations, | |
| 134 constant_stack_parameter_count, | 160 constant_stack_parameter_count, |
| 135 JS_FUNCTION_STUB_MODE, | 161 JS_FUNCTION_STUB_MODE, PASS_ARGUMENTS); |
| 136 PASS_ARGUMENTS); | |
| 137 } | 162 } |
| 138 } | 163 } |
| 139 | 164 |
| 140 | 165 |
| 141 static void InitializeInternalArrayConstructorDescriptor( | 166 static void InitializeInternalArrayConstructorDescriptor( |
| 142 CodeStubInterfaceDescriptor* descriptor, | 167 CodeStub::Major major, CodeStubInterfaceDescriptor* descriptor, |
| 143 int constant_stack_parameter_count) { | 168 int constant_stack_parameter_count) { |
| 144 // register state | 169 // register state |
| 145 // rsi -- context | 170 // rsi -- context |
| 146 // rax -- number of arguments | 171 // rax -- number of arguments |
| 147 // rdi -- constructor function | 172 // rdi -- constructor function |
| 148 Address deopt_handler = Runtime::FunctionForId( | 173 Address deopt_handler = Runtime::FunctionForId( |
| 149 Runtime::kInternalArrayConstructor)->entry; | 174 Runtime::kInternalArrayConstructor)->entry; |
| 150 | 175 |
| 151 if (constant_stack_parameter_count == 0) { | 176 if (constant_stack_parameter_count == 0) { |
| 152 Register registers[] = { rsi, rdi }; | 177 Register registers[] = { rsi, rdi }; |
| 153 descriptor->Initialize(ARRAY_SIZE(registers), registers, | 178 descriptor->Initialize(major, ARRAY_SIZE(registers), registers, |
| 154 deopt_handler, | 179 deopt_handler, NULL, constant_stack_parameter_count, |
| 155 NULL, | |
| 156 constant_stack_parameter_count, | |
| 157 JS_FUNCTION_STUB_MODE); | 180 JS_FUNCTION_STUB_MODE); |
| 158 } else { | 181 } else { |
| 159 // stack param count needs (constructor pointer, and single argument) | 182 // stack param count needs (constructor pointer, and single argument) |
| 160 Register registers[] = { rsi, rdi, rax }; | 183 Register registers[] = { rsi, rdi, rax }; |
| 161 Representation representations[] = { | 184 Representation representations[] = { |
| 162 Representation::Tagged(), | 185 Representation::Tagged(), |
| 163 Representation::Tagged(), | 186 Representation::Tagged(), |
| 164 Representation::Integer32() }; | 187 Representation::Integer32() }; |
| 165 descriptor->Initialize(ARRAY_SIZE(registers), registers, | 188 descriptor->Initialize(major, ARRAY_SIZE(registers), registers, rax, |
| 166 rax, | 189 deopt_handler, representations, |
| 167 deopt_handler, | |
| 168 representations, | |
| 169 constant_stack_parameter_count, | 190 constant_stack_parameter_count, |
| 170 JS_FUNCTION_STUB_MODE, | 191 JS_FUNCTION_STUB_MODE, PASS_ARGUMENTS); |
| 171 PASS_ARGUMENTS); | |
| 172 } | 192 } |
| 173 } | 193 } |
| 174 | 194 |
| 175 | 195 |
| 176 void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( | 196 void ArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( |
| 177 CodeStubInterfaceDescriptor* descriptor) { | 197 CodeStubInterfaceDescriptor* descriptor) { |
| 178 InitializeArrayConstructorDescriptor(descriptor, 0); | 198 InitializeArrayConstructorDescriptor(MajorKey(), descriptor, 0); |
| 179 } | 199 } |
| 180 | 200 |
| 181 | 201 |
| 182 void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor( | 202 void ArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor( |
| 183 CodeStubInterfaceDescriptor* descriptor) { | 203 CodeStubInterfaceDescriptor* descriptor) { |
| 184 InitializeArrayConstructorDescriptor(descriptor, 1); | 204 InitializeArrayConstructorDescriptor(MajorKey(), descriptor, 1); |
| 185 } | 205 } |
| 186 | 206 |
| 187 | 207 |
| 188 void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( | 208 void ArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( |
| 189 CodeStubInterfaceDescriptor* descriptor) { | 209 CodeStubInterfaceDescriptor* descriptor) { |
| 190 InitializeArrayConstructorDescriptor(descriptor, -1); | 210 InitializeArrayConstructorDescriptor(MajorKey(), descriptor, -1); |
| 191 } | 211 } |
| 192 | 212 |
| 193 | 213 |
| 194 void InternalArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( | 214 void InternalArrayNoArgumentConstructorStub::InitializeInterfaceDescriptor( |
| 195 CodeStubInterfaceDescriptor* descriptor) { | 215 CodeStubInterfaceDescriptor* descriptor) { |
| 196 InitializeInternalArrayConstructorDescriptor(descriptor, 0); | 216 InitializeInternalArrayConstructorDescriptor(MajorKey(), descriptor, 0); |
| 197 } | 217 } |
| 198 | 218 |
| 199 | 219 |
| 200 void InternalArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor( | 220 void InternalArraySingleArgumentConstructorStub::InitializeInterfaceDescriptor( |
| 201 CodeStubInterfaceDescriptor* descriptor) { | 221 CodeStubInterfaceDescriptor* descriptor) { |
| 202 InitializeInternalArrayConstructorDescriptor(descriptor, 1); | 222 InitializeInternalArrayConstructorDescriptor(MajorKey(), descriptor, 1); |
| 203 } | 223 } |
| 204 | 224 |
| 205 | 225 |
| 206 void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( | 226 void InternalArrayNArgumentsConstructorStub::InitializeInterfaceDescriptor( |
| 207 CodeStubInterfaceDescriptor* descriptor) { | 227 CodeStubInterfaceDescriptor* descriptor) { |
| 208 InitializeInternalArrayConstructorDescriptor(descriptor, -1); | 228 InitializeInternalArrayConstructorDescriptor(MajorKey(), descriptor, -1); |
| 209 } | 229 } |
| 210 | 230 |
| 211 | 231 |
| 212 void CompareNilICStub::InitializeInterfaceDescriptor( | 232 void CompareNilICStub::InitializeInterfaceDescriptor( |
| 213 CodeStubInterfaceDescriptor* descriptor) { | 233 CodeStubInterfaceDescriptor* descriptor) { |
| 214 Register registers[] = { rsi, rax }; | 234 Register registers[] = { rsi, rax }; |
| 215 descriptor->Initialize(ARRAY_SIZE(registers), registers, | 235 descriptor->Initialize(MajorKey(), ARRAY_SIZE(registers), registers, |
| 216 FUNCTION_ADDR(CompareNilIC_Miss)); | 236 FUNCTION_ADDR(CompareNilIC_Miss)); |
| 217 descriptor->SetMissHandler( | 237 descriptor->SetMissHandler( |
| 218 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate())); | 238 ExternalReference(IC_Utility(IC::kCompareNilIC_Miss), isolate())); |
| 219 } | 239 } |
| 220 | 240 |
| 221 | 241 |
| 222 void ToBooleanStub::InitializeInterfaceDescriptor( | 242 void ToBooleanStub::InitializeInterfaceDescriptor( |
| 223 CodeStubInterfaceDescriptor* descriptor) { | 243 CodeStubInterfaceDescriptor* descriptor) { |
| 224 Register registers[] = { rsi, rax }; | 244 Register registers[] = { rsi, rax }; |
| 225 descriptor->Initialize(ARRAY_SIZE(registers), registers, | 245 descriptor->Initialize(MajorKey(), ARRAY_SIZE(registers), registers, |
| 226 FUNCTION_ADDR(ToBooleanIC_Miss)); | 246 FUNCTION_ADDR(ToBooleanIC_Miss)); |
| 227 descriptor->SetMissHandler( | 247 descriptor->SetMissHandler( |
| 228 ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate())); | 248 ExternalReference(IC_Utility(IC::kToBooleanIC_Miss), isolate())); |
| 229 } | 249 } |
| 230 | 250 |
| 231 | 251 |
| 232 void BinaryOpICStub::InitializeInterfaceDescriptor( | 252 void BinaryOpICStub::InitializeInterfaceDescriptor( |
| 233 CodeStubInterfaceDescriptor* descriptor) { | 253 CodeStubInterfaceDescriptor* descriptor) { |
| 234 Register registers[] = { rsi, rdx, rax }; | 254 Register registers[] = { rsi, rdx, rax }; |
| 235 descriptor->Initialize(ARRAY_SIZE(registers), registers, | 255 descriptor->Initialize(MajorKey(), ARRAY_SIZE(registers), registers, |
| 236 FUNCTION_ADDR(BinaryOpIC_Miss)); | 256 FUNCTION_ADDR(BinaryOpIC_Miss)); |
| 237 descriptor->SetMissHandler( | 257 descriptor->SetMissHandler( |
| 238 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate())); | 258 ExternalReference(IC_Utility(IC::kBinaryOpIC_Miss), isolate())); |
| 239 } | 259 } |
| 240 | 260 |
| 241 | 261 |
| 242 void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor( | 262 void BinaryOpWithAllocationSiteStub::InitializeInterfaceDescriptor( |
| 243 CodeStubInterfaceDescriptor* descriptor) { | 263 CodeStubInterfaceDescriptor* descriptor) { |
| 244 Register registers[] = { rsi, rcx, rdx, rax }; | 264 Register registers[] = { rsi, rcx, rdx, rax }; |
| 245 descriptor->Initialize(ARRAY_SIZE(registers), registers, | 265 descriptor->Initialize(MajorKey(), ARRAY_SIZE(registers), registers, |
| 246 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite)); | 266 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite)); |
| 247 } | 267 } |
| 248 | 268 |
| 249 | 269 |
| 250 void StringAddStub::InitializeInterfaceDescriptor( | 270 void StringAddStub::InitializeInterfaceDescriptor( |
| 251 CodeStubInterfaceDescriptor* descriptor) { | 271 CodeStubInterfaceDescriptor* descriptor) { |
| 252 Register registers[] = { rsi, rdx, rax }; | 272 Register registers[] = { rsi, rdx, rax }; |
| 253 descriptor->Initialize( | 273 descriptor->Initialize(MajorKey(), ARRAY_SIZE(registers), registers, |
| 254 ARRAY_SIZE(registers), registers, | 274 Runtime::FunctionForId(Runtime::kStringAdd)->entry); |
| 255 Runtime::FunctionForId(Runtime::kStringAdd)->entry); | |
| 256 } | 275 } |
| 257 | 276 |
| 258 | 277 |
| 259 void CallDescriptors::InitializeForIsolate(Isolate* isolate) { | 278 void CallDescriptors::InitializeForIsolate(Isolate* isolate) { |
| 260 { | 279 { |
| 261 CallInterfaceDescriptor* descriptor = | 280 CallInterfaceDescriptor* descriptor = |
| 262 isolate->call_descriptor(Isolate::ArgumentAdaptorCall); | 281 isolate->call_descriptor(Isolate::ArgumentAdaptorCall); |
| 263 Register registers[] = { rsi, // context | 282 Register registers[] = { rsi, // context |
| 264 rdi, // JSFunction | 283 rdi, // JSFunction |
| 265 rax, // actual number of arguments | 284 rax, // actual number of arguments |
| (...skipping 2454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2720 // rsp[16] : value | 2739 // rsp[16] : value |
| 2721 // Expected input state with an inline one-element cache: | 2740 // Expected input state with an inline one-element cache: |
| 2722 // rsp[0] : return address | 2741 // rsp[0] : return address |
| 2723 // rsp[8] : offset from return address to location of inline cache | 2742 // rsp[8] : offset from return address to location of inline cache |
| 2724 // rsp[16] : function pointer | 2743 // rsp[16] : function pointer |
| 2725 // rsp[24] : value | 2744 // rsp[24] : value |
| 2726 // Returns a bitwise zero to indicate that the value | 2745 // Returns a bitwise zero to indicate that the value |
| 2727 // is and instance of the function and anything else to | 2746 // is and instance of the function and anything else to |
| 2728 // indicate that the value is not an instance. | 2747 // indicate that the value is not an instance. |
| 2729 | 2748 |
| 2749 // Fixed register usage throughout the stub. |
| 2750 Register object = rax; // Object (lhs). |
| 2751 Register map = rbx; // Map of the object. |
| 2752 Register function = rdx; // Function (rhs). |
| 2753 Register prototype = rdi; // Prototype of the function. |
| 2754 Register scratch = rcx; |
| 2755 |
| 2730 static const int kOffsetToMapCheckValue = 2; | 2756 static const int kOffsetToMapCheckValue = 2; |
| 2731 static const int kOffsetToResultValue = kPointerSize == kInt64Size ? 18 : 14; | 2757 static const int kOffsetToResultValue = kPointerSize == kInt64Size ? 18 : 14; |
| 2732 // The last 4 bytes of the instruction sequence | 2758 // The last 4 bytes of the instruction sequence |
| 2733 // movp(rdi, FieldOperand(rax, HeapObject::kMapOffset)) | 2759 // movp(rdi, FieldOperand(rax, HeapObject::kMapOffset)) |
| 2734 // Move(kScratchRegister, Factory::the_hole_value()) | 2760 // Move(kScratchRegister, Factory::the_hole_value()) |
| 2735 // in front of the hole value address. | 2761 // in front of the hole value address. |
| 2736 static const unsigned int kWordBeforeMapCheckValue = | 2762 static const unsigned int kWordBeforeMapCheckValue = |
| 2737 kPointerSize == kInt64Size ? 0xBA49FF78 : 0xBA41FF78; | 2763 kPointerSize == kInt64Size ? 0xBA49FF78 : 0xBA41FF78; |
| 2738 // The last 4 bytes of the instruction sequence | 2764 // The last 4 bytes of the instruction sequence |
| 2739 // __ j(not_equal, &cache_miss); | 2765 // __ j(not_equal, &cache_miss); |
| 2740 // __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex); | 2766 // __ LoadRoot(ToRegister(instr->result()), Heap::kTheHoleValueRootIndex); |
| 2741 // before the offset of the hole value in the root array. | 2767 // before the offset of the hole value in the root array. |
| 2742 static const unsigned int kWordBeforeResultValue = | 2768 static const unsigned int kWordBeforeResultValue = |
| 2743 kPointerSize == kInt64Size ? 0x458B4906 : 0x458B4106; | 2769 kPointerSize == kInt64Size ? 0x458B4906 : 0x458B4106; |
| 2744 // Only the inline check flag is supported on X64. | 2770 |
| 2745 ASSERT(flags_ == kNoFlags || HasCallSiteInlineCheck()); | |
| 2746 int extra_argument_offset = HasCallSiteInlineCheck() ? 1 : 0; | 2771 int extra_argument_offset = HasCallSiteInlineCheck() ? 1 : 0; |
| 2747 | 2772 |
| 2748 // Get the object - go slow case if it's a smi. | 2773 ASSERT_EQ(object.code(), InstanceofStub::left().code()); |
| 2774 ASSERT_EQ(function.code(), InstanceofStub::right().code()); |
| 2775 |
| 2776 // Get the object and function - they are always both needed. |
| 2777 // Go slow case if the object is a smi. |
| 2749 Label slow; | 2778 Label slow; |
| 2750 StackArgumentsAccessor args(rsp, 2 + extra_argument_offset, | 2779 StackArgumentsAccessor args(rsp, 2 + extra_argument_offset, |
| 2751 ARGUMENTS_DONT_CONTAIN_RECEIVER); | 2780 ARGUMENTS_DONT_CONTAIN_RECEIVER); |
| 2752 __ movp(rax, args.GetArgumentOperand(0)); | 2781 if (!HasArgsInRegisters()) { |
| 2753 __ JumpIfSmi(rax, &slow); | 2782 __ movp(object, args.GetArgumentOperand(0)); |
| 2783 __ movp(function, args.GetArgumentOperand(1)); |
| 2784 } |
| 2785 __ JumpIfSmi(object, &slow); |
| 2754 | 2786 |
| 2755 // Check that the left hand is a JS object. Leave its map in rax. | 2787 // Check that the left hand is a JS object. Leave its map in rax. |
| 2756 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax); | 2788 __ CmpObjectType(object, FIRST_SPEC_OBJECT_TYPE, map); |
| 2757 __ j(below, &slow); | 2789 __ j(below, &slow); |
| 2758 __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE); | 2790 __ CmpInstanceType(map, LAST_SPEC_OBJECT_TYPE); |
| 2759 __ j(above, &slow); | 2791 __ j(above, &slow); |
| 2760 | 2792 |
| 2761 // Get the prototype of the function. | |
| 2762 __ movp(rdx, args.GetArgumentOperand(1)); | |
| 2763 // rdx is function, rax is map. | |
| 2764 | |
| 2765 // If there is a call site cache don't look in the global cache, but do the | 2793 // If there is a call site cache don't look in the global cache, but do the |
| 2766 // real lookup and update the call site cache. | 2794 // real lookup and update the call site cache. |
| 2767 if (!HasCallSiteInlineCheck()) { | 2795 if (!HasCallSiteInlineCheck() && !ReturnTrueFalseObject()) { |
| 2768 // Look up the function and the map in the instanceof cache. | 2796 // Look up the function and the map in the instanceof cache. |
| 2769 Label miss; | 2797 Label miss; |
| 2770 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); | 2798 __ CompareRoot(function, Heap::kInstanceofCacheFunctionRootIndex); |
| 2771 __ j(not_equal, &miss, Label::kNear); | 2799 __ j(not_equal, &miss, Label::kNear); |
| 2772 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); | 2800 __ CompareRoot(map, Heap::kInstanceofCacheMapRootIndex); |
| 2773 __ j(not_equal, &miss, Label::kNear); | 2801 __ j(not_equal, &miss, Label::kNear); |
| 2774 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); | 2802 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
| 2775 __ ret(2 * kPointerSize); | 2803 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
| 2776 __ bind(&miss); | 2804 __ bind(&miss); |
| 2777 } | 2805 } |
| 2778 | 2806 |
| 2779 __ TryGetFunctionPrototype(rdx, rbx, &slow, true); | 2807 // Get the prototype of the function. |
| 2808 __ TryGetFunctionPrototype(function, prototype, &slow, true); |
| 2780 | 2809 |
| 2781 // Check that the function prototype is a JS object. | 2810 // Check that the function prototype is a JS object. |
| 2782 __ JumpIfSmi(rbx, &slow); | 2811 __ JumpIfSmi(prototype, &slow); |
| 2783 __ CmpObjectType(rbx, FIRST_SPEC_OBJECT_TYPE, kScratchRegister); | 2812 __ CmpObjectType(prototype, FIRST_SPEC_OBJECT_TYPE, kScratchRegister); |
| 2784 __ j(below, &slow); | 2813 __ j(below, &slow); |
| 2785 __ CmpInstanceType(kScratchRegister, LAST_SPEC_OBJECT_TYPE); | 2814 __ CmpInstanceType(kScratchRegister, LAST_SPEC_OBJECT_TYPE); |
| 2786 __ j(above, &slow); | 2815 __ j(above, &slow); |
| 2787 | 2816 |
| 2788 // Register mapping: | 2817 // Update the global instanceof or call site inlined cache with the current |
| 2789 // rax is object map. | 2818 // map and function. The cached answer will be set when it is known below. |
| 2790 // rdx is function. | |
| 2791 // rbx is function prototype. | |
| 2792 if (!HasCallSiteInlineCheck()) { | 2819 if (!HasCallSiteInlineCheck()) { |
| 2793 __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); | 2820 __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex); |
| 2794 __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex); | 2821 __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex); |
| 2795 } else { | 2822 } else { |
| 2823 // The constants for the code patching are based on push instructions |
| 2824 // at the call site. |
| 2825 ASSERT(!HasArgsInRegisters()); |
| 2796 // Get return address and delta to inlined map check. | 2826 // Get return address and delta to inlined map check. |
| 2797 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); | 2827 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); |
| 2798 __ subp(kScratchRegister, args.GetArgumentOperand(2)); | 2828 __ subp(kScratchRegister, args.GetArgumentOperand(2)); |
| 2799 if (FLAG_debug_code) { | 2829 if (FLAG_debug_code) { |
| 2800 __ movl(rdi, Immediate(kWordBeforeMapCheckValue)); | 2830 __ movl(scratch, Immediate(kWordBeforeMapCheckValue)); |
| 2801 __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), rdi); | 2831 __ cmpl(Operand(kScratchRegister, kOffsetToMapCheckValue - 4), scratch); |
| 2802 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCheck); | 2832 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheCheck); |
| 2803 } | 2833 } |
| 2804 __ movp(kScratchRegister, | 2834 __ movp(kScratchRegister, |
| 2805 Operand(kScratchRegister, kOffsetToMapCheckValue)); | 2835 Operand(kScratchRegister, kOffsetToMapCheckValue)); |
| 2806 __ movp(Operand(kScratchRegister, 0), rax); | 2836 __ movp(Operand(kScratchRegister, 0), map); |
| 2807 } | 2837 } |
| 2808 | 2838 |
| 2809 __ movp(rcx, FieldOperand(rax, Map::kPrototypeOffset)); | |
| 2810 | |
| 2811 // Loop through the prototype chain looking for the function prototype. | 2839 // Loop through the prototype chain looking for the function prototype. |
| 2840 __ movp(scratch, FieldOperand(map, Map::kPrototypeOffset)); |
| 2812 Label loop, is_instance, is_not_instance; | 2841 Label loop, is_instance, is_not_instance; |
| 2813 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); | 2842 __ LoadRoot(kScratchRegister, Heap::kNullValueRootIndex); |
| 2814 __ bind(&loop); | 2843 __ bind(&loop); |
| 2815 __ cmpp(rcx, rbx); | 2844 __ cmpp(scratch, prototype); |
| 2816 __ j(equal, &is_instance, Label::kNear); | 2845 __ j(equal, &is_instance, Label::kNear); |
| 2817 __ cmpp(rcx, kScratchRegister); | 2846 __ cmpp(scratch, kScratchRegister); |
| 2818 // The code at is_not_instance assumes that kScratchRegister contains a | 2847 // The code at is_not_instance assumes that kScratchRegister contains a |
| 2819 // non-zero GCable value (the null object in this case). | 2848 // non-zero GCable value (the null object in this case). |
| 2820 __ j(equal, &is_not_instance, Label::kNear); | 2849 __ j(equal, &is_not_instance, Label::kNear); |
| 2821 __ movp(rcx, FieldOperand(rcx, HeapObject::kMapOffset)); | 2850 __ movp(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
| 2822 __ movp(rcx, FieldOperand(rcx, Map::kPrototypeOffset)); | 2851 __ movp(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); |
| 2823 __ jmp(&loop); | 2852 __ jmp(&loop); |
| 2824 | 2853 |
| 2825 __ bind(&is_instance); | 2854 __ bind(&is_instance); |
| 2826 if (!HasCallSiteInlineCheck()) { | 2855 if (!HasCallSiteInlineCheck()) { |
| 2827 __ xorl(rax, rax); | 2856 __ xorl(rax, rax); |
| 2828 // Store bitwise zero in the cache. This is a Smi in GC terms. | 2857 // Store bitwise zero in the cache. This is a Smi in GC terms. |
| 2829 STATIC_ASSERT(kSmiTag == 0); | 2858 STATIC_ASSERT(kSmiTag == 0); |
| 2830 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); | 2859 __ StoreRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
| 2860 if (ReturnTrueFalseObject()) { |
| 2861 __ LoadRoot(rax, Heap::kTrueValueRootIndex); |
| 2862 } |
| 2831 } else { | 2863 } else { |
| 2832 // Store offset of true in the root array at the inline check site. | 2864 // Store offset of true in the root array at the inline check site. |
| 2833 int true_offset = 0x100 + | 2865 int true_offset = 0x100 + |
| 2834 (Heap::kTrueValueRootIndex << kPointerSizeLog2) - kRootRegisterBias; | 2866 (Heap::kTrueValueRootIndex << kPointerSizeLog2) - kRootRegisterBias; |
| 2835 // Assert it is a 1-byte signed value. | 2867 // Assert it is a 1-byte signed value. |
| 2836 ASSERT(true_offset >= 0 && true_offset < 0x100); | 2868 ASSERT(true_offset >= 0 && true_offset < 0x100); |
| 2837 __ movl(rax, Immediate(true_offset)); | 2869 __ movl(rax, Immediate(true_offset)); |
| 2838 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); | 2870 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); |
| 2839 __ subp(kScratchRegister, args.GetArgumentOperand(2)); | 2871 __ subp(kScratchRegister, args.GetArgumentOperand(2)); |
| 2840 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); | 2872 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); |
| 2841 if (FLAG_debug_code) { | 2873 if (FLAG_debug_code) { |
| 2842 __ movl(rax, Immediate(kWordBeforeResultValue)); | 2874 __ movl(rax, Immediate(kWordBeforeResultValue)); |
| 2843 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); | 2875 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); |
| 2844 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); | 2876 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); |
| 2845 } | 2877 } |
| 2846 __ Set(rax, 0); | 2878 if (!ReturnTrueFalseObject()) { |
| 2879 __ Set(rax, 0); |
| 2880 } |
| 2847 } | 2881 } |
| 2848 __ ret((2 + extra_argument_offset) * kPointerSize); | 2882 __ ret(((HasArgsInRegisters() ? 0 : 2) + extra_argument_offset) * |
| 2883 kPointerSize); |
| 2849 | 2884 |
| 2850 __ bind(&is_not_instance); | 2885 __ bind(&is_not_instance); |
| 2851 if (!HasCallSiteInlineCheck()) { | 2886 if (!HasCallSiteInlineCheck()) { |
| 2852 // We have to store a non-zero value in the cache. | 2887 // We have to store a non-zero value in the cache. |
| 2853 __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex); | 2888 __ StoreRoot(kScratchRegister, Heap::kInstanceofCacheAnswerRootIndex); |
| 2889 if (ReturnTrueFalseObject()) { |
| 2890 __ LoadRoot(rax, Heap::kFalseValueRootIndex); |
| 2891 } |
| 2854 } else { | 2892 } else { |
| 2855 // Store offset of false in the root array at the inline check site. | 2893 // Store offset of false in the root array at the inline check site. |
| 2856 int false_offset = 0x100 + | 2894 int false_offset = 0x100 + |
| 2857 (Heap::kFalseValueRootIndex << kPointerSizeLog2) - kRootRegisterBias; | 2895 (Heap::kFalseValueRootIndex << kPointerSizeLog2) - kRootRegisterBias; |
| 2858 // Assert it is a 1-byte signed value. | 2896 // Assert it is a 1-byte signed value. |
| 2859 ASSERT(false_offset >= 0 && false_offset < 0x100); | 2897 ASSERT(false_offset >= 0 && false_offset < 0x100); |
| 2860 __ movl(rax, Immediate(false_offset)); | 2898 __ movl(rax, Immediate(false_offset)); |
| 2861 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); | 2899 __ movq(kScratchRegister, StackOperandForReturnAddress(0)); |
| 2862 __ subp(kScratchRegister, args.GetArgumentOperand(2)); | 2900 __ subp(kScratchRegister, args.GetArgumentOperand(2)); |
| 2863 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); | 2901 __ movb(Operand(kScratchRegister, kOffsetToResultValue), rax); |
| 2864 if (FLAG_debug_code) { | 2902 if (FLAG_debug_code) { |
| 2865 __ movl(rax, Immediate(kWordBeforeResultValue)); | 2903 __ movl(rax, Immediate(kWordBeforeResultValue)); |
| 2866 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); | 2904 __ cmpl(Operand(kScratchRegister, kOffsetToResultValue - 4), rax); |
| 2867 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); | 2905 __ Assert(equal, kInstanceofStubUnexpectedCallSiteCacheMov); |
| 2868 } | 2906 } |
| 2869 } | 2907 } |
| 2870 __ ret((2 + extra_argument_offset) * kPointerSize); | 2908 __ ret(((HasArgsInRegisters() ? 0 : 2) + extra_argument_offset) * |
| 2909 kPointerSize); |
| 2871 | 2910 |
| 2872 // Slow-case: Go through the JavaScript implementation. | 2911 // Slow-case: Go through the JavaScript implementation. |
| 2873 __ bind(&slow); | 2912 __ bind(&slow); |
| 2874 if (HasCallSiteInlineCheck()) { | 2913 if (!ReturnTrueFalseObject()) { |
| 2875 // Remove extra value from the stack. | 2914 // Tail call the builtin which returns 0 or 1. |
| 2876 __ PopReturnAddressTo(rcx); | 2915 ASSERT(!HasArgsInRegisters()); |
| 2877 __ Pop(rax); | 2916 if (HasCallSiteInlineCheck()) { |
| 2878 __ PushReturnAddressFrom(rcx); | 2917 // Remove extra value from the stack. |
| 2918 __ PopReturnAddressTo(rcx); |
| 2919 __ Pop(rax); |
| 2920 __ PushReturnAddressFrom(rcx); |
| 2921 } |
| 2922 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
| 2923 } else { |
| 2924 // Call the builtin and convert 0/1 to true/false. |
| 2925 { |
| 2926 FrameScope scope(masm, StackFrame::INTERNAL); |
| 2927 __ Push(object); |
| 2928 __ Push(function); |
| 2929 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); |
| 2930 } |
| 2931 Label true_value, done; |
| 2932 __ testq(rax, rax); |
| 2933 __ j(zero, &true_value, Label::kNear); |
| 2934 __ LoadRoot(rax, Heap::kFalseValueRootIndex); |
| 2935 __ jmp(&done, Label::kNear); |
| 2936 __ bind(&true_value); |
| 2937 __ LoadRoot(rax, Heap::kTrueValueRootIndex); |
| 2938 __ bind(&done); |
| 2939 __ ret(((HasArgsInRegisters() ? 0 : 2) + extra_argument_offset) * |
| 2940 kPointerSize); |
| 2879 } | 2941 } |
| 2880 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | |
| 2881 } | 2942 } |
| 2882 | 2943 |
| 2883 | 2944 |
| 2884 // Passing arguments in registers is not supported. | 2945 // Passing arguments in registers is not supported. |
| 2885 Register InstanceofStub::left() { return no_reg; } | 2946 Register InstanceofStub::left() { return rax; } |
| 2886 | 2947 |
| 2887 | 2948 |
| 2888 Register InstanceofStub::right() { return no_reg; } | 2949 Register InstanceofStub::right() { return rdx; } |
| 2889 | 2950 |
| 2890 | 2951 |
| 2891 // ------------------------------------------------------------------------- | 2952 // ------------------------------------------------------------------------- |
| 2892 // StringCharCodeAtGenerator | 2953 // StringCharCodeAtGenerator |
| 2893 | 2954 |
| 2894 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 2955 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
| 2895 Label flat_string; | 2956 Label flat_string; |
| 2896 Label ascii_string; | 2957 Label ascii_string; |
| 2897 Label got_char_code; | 2958 Label got_char_code; |
| 2898 Label sliced_string; | 2959 Label sliced_string; |
| (...skipping 2023 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4922 return_value_operand, | 4983 return_value_operand, |
| 4923 NULL); | 4984 NULL); |
| 4924 } | 4985 } |
| 4925 | 4986 |
| 4926 | 4987 |
| 4927 #undef __ | 4988 #undef __ |
| 4928 | 4989 |
| 4929 } } // namespace v8::internal | 4990 } } // namespace v8::internal |
| 4930 | 4991 |
| 4931 #endif // V8_TARGET_ARCH_X64 | 4992 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |