| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 #if V8_TARGET_ARCH_X64 | 5 #if V8_TARGET_ARCH_X64 |
| 6 | 6 |
| 7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
| 8 #include "src/codegen.h" | 8 #include "src/codegen.h" |
| 9 #include "src/deoptimizer.h" | 9 #include "src/deoptimizer.h" |
| 10 #include "src/full-codegen/full-codegen.h" | 10 #include "src/full-codegen/full-codegen.h" |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 | 112 |
| 113 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode); | 113 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode); |
| 114 GenerateTailCallToReturnedCode(masm); | 114 GenerateTailCallToReturnedCode(masm); |
| 115 | 115 |
| 116 __ bind(&ok); | 116 __ bind(&ok); |
| 117 GenerateTailCallToSharedCode(masm); | 117 GenerateTailCallToSharedCode(masm); |
| 118 } | 118 } |
| 119 | 119 |
| 120 | 120 |
| 121 static void Generate_JSConstructStubHelper(MacroAssembler* masm, | 121 static void Generate_JSConstructStubHelper(MacroAssembler* masm, |
| 122 bool is_api_function) { | 122 bool is_api_function, |
| 123 bool create_implicit_receiver) { |
| 123 // ----------- S t a t e ------------- | 124 // ----------- S t a t e ------------- |
| 124 // -- rax: number of arguments | 125 // -- rax: number of arguments |
| 125 // -- rdi: constructor function | 126 // -- rdi: constructor function |
| 126 // -- rbx: allocation site or undefined | 127 // -- rbx: allocation site or undefined |
| 127 // -- rdx: new target | 128 // -- rdx: new target |
| 128 // ----------------------------------- | 129 // ----------------------------------- |
| 129 | 130 |
| 130 // Enter a construct frame. | 131 // Enter a construct frame. |
| 131 { | 132 { |
| 132 FrameScope scope(masm, StackFrame::CONSTRUCT); | 133 FrameScope scope(masm, StackFrame::CONSTRUCT); |
| 133 | 134 |
| 134 // Preserve the incoming parameters on the stack. | 135 // Preserve the incoming parameters on the stack. |
| 135 __ AssertUndefinedOrAllocationSite(rbx); | 136 __ AssertUndefinedOrAllocationSite(rbx); |
| 136 __ Push(rbx); | 137 __ Push(rbx); |
| 137 __ Integer32ToSmi(rax, rax); | 138 __ Integer32ToSmi(rcx, rax); |
| 138 __ Push(rax); | 139 __ Push(rcx); |
| 139 __ Push(rdi); | |
| 140 __ Push(rdx); | |
| 141 | 140 |
| 142 // Try to allocate the object without transitioning into C code. If any of | 141 if (create_implicit_receiver) { |
| 143 // the preconditions is not met, the code bails out to the runtime call. | 142 __ Push(rdi); |
| 144 Label rt_call, allocated; | 143 __ Push(rdx); |
| 145 if (FLAG_inline_new) { | |
| 146 // Verify that the new target is a JSFunction. | |
| 147 __ CmpObjectType(rdx, JS_FUNCTION_TYPE, rbx); | |
| 148 __ j(not_equal, &rt_call); | |
| 149 | 144 |
| 150 // Load the initial map and verify that it is in fact a map. | 145 // Try to allocate the object without transitioning into C code. If any of |
| 151 // rdx: new target | 146 // the preconditions is not met, the code bails out to the runtime call. |
| 152 __ movp(rax, FieldOperand(rdx, JSFunction::kPrototypeOrInitialMapOffset)); | 147 Label rt_call, allocated; |
| 153 // Will both indicate a NULL and a Smi | 148 if (FLAG_inline_new) { |
| 154 DCHECK(kSmiTag == 0); | 149 // Verify that the new target is a JSFunction. |
| 155 __ JumpIfSmi(rax, &rt_call); | 150 __ CmpObjectType(rdx, JS_FUNCTION_TYPE, rbx); |
| 156 // rdi: constructor | 151 __ j(not_equal, &rt_call); |
| 157 // rax: initial map (if proven valid below) | |
| 158 __ CmpObjectType(rax, MAP_TYPE, rbx); | |
| 159 __ j(not_equal, &rt_call); | |
| 160 | 152 |
| 161 // Fall back to runtime if the expected base constructor and base | 153 // Load the initial map and verify that it is in fact a map. |
| 162 // constructor differ. | 154 // rdx: new target |
| 163 __ cmpp(rdi, FieldOperand(rax, Map::kConstructorOrBackPointerOffset)); | 155 __ movp(rax, |
| 164 __ j(not_equal, &rt_call); | 156 FieldOperand(rdx, JSFunction::kPrototypeOrInitialMapOffset)); |
| 157 // Will both indicate a NULL and a Smi |
| 158 DCHECK(kSmiTag == 0); |
| 159 __ JumpIfSmi(rax, &rt_call); |
| 160 // rdi: constructor |
| 161 // rax: initial map (if proven valid below) |
| 162 __ CmpObjectType(rax, MAP_TYPE, rbx); |
| 163 __ j(not_equal, &rt_call); |
| 165 | 164 |
| 166 // Check that the constructor is not constructing a JSFunction (see | 165 // Fall back to runtime if the expected base constructor and base |
| 167 // comments in Runtime_NewObject in runtime.cc). In which case the | 166 // constructor differ. |
| 168 // initial map's instance type would be JS_FUNCTION_TYPE. | 167 __ cmpp(rdi, FieldOperand(rax, Map::kConstructorOrBackPointerOffset)); |
| 169 // rdi: constructor | 168 __ j(not_equal, &rt_call); |
| 170 // rax: initial map | |
| 171 __ CmpInstanceType(rax, JS_FUNCTION_TYPE); | |
| 172 __ j(equal, &rt_call); | |
| 173 if (!is_api_function) { | |
| 174 Label allocate; | |
| 175 // The code below relies on these assumptions. | |
| 176 STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32); | |
| 177 // Check if slack tracking is enabled. | |
| 178 __ movl(rsi, FieldOperand(rax, Map::kBitField3Offset)); | |
| 179 __ shrl(rsi, Immediate(Map::Counter::kShift)); | |
| 180 __ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd)); | |
| 181 __ j(less, &allocate); | |
| 182 // Decrease generous allocation count. | |
| 183 __ subl(FieldOperand(rax, Map::kBitField3Offset), | |
| 184 Immediate(1 << Map::Counter::kShift)); | |
| 185 | 169 |
| 186 __ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd)); | 170 if (!is_api_function) { |
| 187 __ j(not_equal, &allocate); | 171 Label allocate; |
| 172 // The code below relies on these assumptions. |
| 173 STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32); |
| 174 // Check if slack tracking is enabled. |
| 175 __ movl(rsi, FieldOperand(rax, Map::kBitField3Offset)); |
| 176 __ shrl(rsi, Immediate(Map::Counter::kShift)); |
| 177 __ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd)); |
| 178 __ j(less, &allocate); |
| 179 // Decrease generous allocation count. |
| 180 __ subl(FieldOperand(rax, Map::kBitField3Offset), |
| 181 Immediate(1 << Map::Counter::kShift)); |
| 188 | 182 |
| 189 __ Push(rax); | 183 __ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd)); |
| 190 __ Push(rdx); | 184 __ j(not_equal, &allocate); |
| 191 __ Push(rdi); | |
| 192 | 185 |
| 193 __ Push(rax); // initial map | 186 __ Push(rax); |
| 194 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1); | 187 __ Push(rdx); |
| 188 __ Push(rdi); |
| 195 | 189 |
| 196 __ Pop(rdi); | 190 __ Push(rax); // initial map |
| 197 __ Pop(rdx); | 191 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1); |
| 198 __ Pop(rax); | |
| 199 __ movl(rsi, Immediate(Map::kSlackTrackingCounterEnd - 1)); | |
| 200 | 192 |
| 201 __ bind(&allocate); | 193 __ Pop(rdi); |
| 194 __ Pop(rdx); |
| 195 __ Pop(rax); |
| 196 __ movl(rsi, Immediate(Map::kSlackTrackingCounterEnd - 1)); |
| 197 |
| 198 __ bind(&allocate); |
| 199 } |
| 200 |
| 201 // Now allocate the JSObject on the heap. |
| 202 __ movzxbp(rdi, FieldOperand(rax, Map::kInstanceSizeOffset)); |
| 203 __ shlp(rdi, Immediate(kPointerSizeLog2)); |
| 204 // rdi: size of new object |
| 205 __ Allocate(rdi, rbx, rdi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); |
| 206 // Allocated the JSObject, now initialize the fields. |
| 207 // rax: initial map |
| 208 // rbx: JSObject (not HeapObject tagged - the actual address). |
| 209 // rdi: start of next object |
| 210 __ movp(Operand(rbx, JSObject::kMapOffset), rax); |
| 211 __ LoadRoot(rcx, Heap::kEmptyFixedArrayRootIndex); |
| 212 __ movp(Operand(rbx, JSObject::kPropertiesOffset), rcx); |
| 213 __ movp(Operand(rbx, JSObject::kElementsOffset), rcx); |
| 214 // Set extra fields in the newly allocated object. |
| 215 // rax: initial map |
| 216 // rbx: JSObject |
| 217 // rdi: start of next object |
| 218 // rsi: slack tracking counter (non-API function case) |
| 219 __ leap(rcx, Operand(rbx, JSObject::kHeaderSize)); |
| 220 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); |
| 221 if (!is_api_function) { |
| 222 Label no_inobject_slack_tracking; |
| 223 |
| 224 // Check if slack tracking is enabled. |
| 225 __ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd)); |
| 226 __ j(less, &no_inobject_slack_tracking); |
| 227 |
| 228 // Allocate object with a slack. |
| 229 __ movzxbp( |
| 230 rsi, |
| 231 FieldOperand( |
| 232 rax, |
| 233 Map::kInObjectPropertiesOrConstructorFunctionIndexOffset)); |
| 234 __ movzxbp(rax, FieldOperand(rax, Map::kUnusedPropertyFieldsOffset)); |
| 235 __ subp(rsi, rax); |
| 236 __ leap(rsi, |
| 237 Operand(rbx, rsi, times_pointer_size, JSObject::kHeaderSize)); |
| 238 // rsi: offset of first field after pre-allocated fields |
| 239 if (FLAG_debug_code) { |
| 240 __ cmpp(rsi, rdi); |
| 241 __ Assert(less_equal, |
| 242 kUnexpectedNumberOfPreAllocatedPropertyFields); |
| 243 } |
| 244 __ InitializeFieldsWithFiller(rcx, rsi, rdx); |
| 245 __ LoadRoot(rdx, Heap::kOnePointerFillerMapRootIndex); |
| 246 // Fill the remaining fields with one pointer filler map. |
| 247 |
| 248 __ bind(&no_inobject_slack_tracking); |
| 249 } |
| 250 |
| 251 __ InitializeFieldsWithFiller(rcx, rdi, rdx); |
| 252 |
| 253 // Add the object tag to make the JSObject real, so that we can continue |
| 254 // and jump into the continuation code at any time from now on. |
| 255 // rbx: JSObject (untagged) |
| 256 __ orp(rbx, Immediate(kHeapObjectTag)); |
| 257 |
| 258 // Continue with JSObject being successfully allocated |
| 259 // rbx: JSObject (tagged) |
| 260 __ jmp(&allocated); |
| 202 } | 261 } |
| 203 | 262 |
| 204 // Now allocate the JSObject on the heap. | 263 // Allocate the new receiver object using the runtime call. |
| 205 __ movzxbp(rdi, FieldOperand(rax, Map::kInstanceSizeOffset)); | 264 // rdx: new target |
| 206 __ shlp(rdi, Immediate(kPointerSizeLog2)); | 265 __ bind(&rt_call); |
| 207 // rdi: size of new object | 266 int offset = kPointerSize; |
| 208 __ Allocate(rdi, | |
| 209 rbx, | |
| 210 rdi, | |
| 211 no_reg, | |
| 212 &rt_call, | |
| 213 NO_ALLOCATION_FLAGS); | |
| 214 // Allocated the JSObject, now initialize the fields. | |
| 215 // rax: initial map | |
| 216 // rbx: JSObject (not HeapObject tagged - the actual address). | |
| 217 // rdi: start of next object | |
| 218 __ movp(Operand(rbx, JSObject::kMapOffset), rax); | |
| 219 __ LoadRoot(rcx, Heap::kEmptyFixedArrayRootIndex); | |
| 220 __ movp(Operand(rbx, JSObject::kPropertiesOffset), rcx); | |
| 221 __ movp(Operand(rbx, JSObject::kElementsOffset), rcx); | |
| 222 // Set extra fields in the newly allocated object. | |
| 223 // rax: initial map | |
| 224 // rbx: JSObject | |
| 225 // rdi: start of next object | |
| 226 // rsi: slack tracking counter (non-API function case) | |
| 227 __ leap(rcx, Operand(rbx, JSObject::kHeaderSize)); | |
| 228 __ LoadRoot(rdx, Heap::kUndefinedValueRootIndex); | |
| 229 if (!is_api_function) { | |
| 230 Label no_inobject_slack_tracking; | |
| 231 | 267 |
| 232 // Check if slack tracking is enabled. | 268 // Must restore rsi (context) and rdi (constructor) before calling |
| 233 __ cmpl(rsi, Immediate(Map::kSlackTrackingCounterEnd)); | 269 // runtime. |
| 234 __ j(less, &no_inobject_slack_tracking); | 270 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 271 __ movp(rdi, Operand(rsp, offset)); |
| 272 __ Push(rdi); // constructor function |
| 273 __ Push(rdx); // new target |
| 274 __ CallRuntime(Runtime::kNewObject, 2); |
| 275 __ movp(rbx, rax); // store result in rbx |
| 235 | 276 |
| 236 // Allocate object with a slack. | 277 // New object allocated. |
| 237 __ movzxbp( | 278 // rbx: newly allocated object |
| 238 rsi, | 279 __ bind(&allocated); |
| 239 FieldOperand( | |
| 240 rax, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset)); | |
| 241 __ movzxbp(rax, FieldOperand(rax, Map::kUnusedPropertyFieldsOffset)); | |
| 242 __ subp(rsi, rax); | |
| 243 __ leap(rsi, | |
| 244 Operand(rbx, rsi, times_pointer_size, JSObject::kHeaderSize)); | |
| 245 // rsi: offset of first field after pre-allocated fields | |
| 246 if (FLAG_debug_code) { | |
| 247 __ cmpp(rsi, rdi); | |
| 248 __ Assert(less_equal, | |
| 249 kUnexpectedNumberOfPreAllocatedPropertyFields); | |
| 250 } | |
| 251 __ InitializeFieldsWithFiller(rcx, rsi, rdx); | |
| 252 __ LoadRoot(rdx, Heap::kOnePointerFillerMapRootIndex); | |
| 253 // Fill the remaining fields with one pointer filler map. | |
| 254 | 280 |
| 255 __ bind(&no_inobject_slack_tracking); | 281 // Restore the parameters. |
| 256 } | 282 __ Pop(rdx); |
| 283 __ Pop(rdi); |
| 257 | 284 |
| 258 __ InitializeFieldsWithFiller(rcx, rdi, rdx); | 285 // Retrieve smi-tagged arguments count from the stack. |
| 259 | 286 __ movp(rax, Operand(rsp, 0)); |
| 260 // Add the object tag to make the JSObject real, so that we can continue | 287 __ SmiToInteger32(rax, rax); |
| 261 // and jump into the continuation code at any time from now on. | |
| 262 // rbx: JSObject (untagged) | |
| 263 __ orp(rbx, Immediate(kHeapObjectTag)); | |
| 264 | |
| 265 // Continue with JSObject being successfully allocated | |
| 266 // rbx: JSObject (tagged) | |
| 267 __ jmp(&allocated); | |
| 268 } | 288 } |
| 269 | 289 |
| 270 // Allocate the new receiver object using the runtime call. | |
| 271 // rdx: new target | |
| 272 __ bind(&rt_call); | |
| 273 int offset = kPointerSize; | |
| 274 | |
| 275 // Must restore rsi (context) and rdi (constructor) before calling runtime. | |
| 276 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | |
| 277 __ movp(rdi, Operand(rsp, offset)); | |
| 278 __ Push(rdi); // constructor function | |
| 279 __ Push(rdx); // new target | |
| 280 __ CallRuntime(Runtime::kNewObject, 2); | |
| 281 __ movp(rbx, rax); // store result in rbx | |
| 282 | |
| 283 // New object allocated. | |
| 284 // rbx: newly allocated object | |
| 285 __ bind(&allocated); | |
| 286 | |
| 287 // Restore the parameters. | |
| 288 __ Pop(rdx); | |
| 289 __ Pop(rdi); | |
| 290 | |
| 291 // Retrieve smi-tagged arguments count from the stack. | |
| 292 __ movp(rax, Operand(rsp, 0)); | |
| 293 __ SmiToInteger32(rax, rax); | |
| 294 | |
| 295 // Push new.target onto the construct frame. This is stored just below the | 290 // Push new.target onto the construct frame. This is stored just below the |
| 296 // receiver on the stack. | 291 // receiver on the stack. |
| 297 __ Push(rdx); | 292 __ Push(rdx); |
| 298 | 293 |
| 299 // Push the allocated receiver to the stack. We need two copies | 294 if (create_implicit_receiver) { |
| 300 // because we may have to return the original one and the calling | 295 // Push the allocated receiver to the stack. We need two copies |
| 301 // conventions dictate that the called function pops the receiver. | 296 // because we may have to return the original one and the calling |
| 302 __ Push(rbx); | 297 // conventions dictate that the called function pops the receiver. |
| 303 __ Push(rbx); | 298 __ Push(rbx); |
| 299 __ Push(rbx); |
| 300 } else { |
| 301 __ PushRoot(Heap::kTheHoleValueRootIndex); |
| 302 } |
| 304 | 303 |
| 305 // Set up pointer to last argument. | 304 // Set up pointer to last argument. |
| 306 __ leap(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset)); | 305 __ leap(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset)); |
| 307 | 306 |
| 308 // Copy arguments and receiver to the expression stack. | 307 // Copy arguments and receiver to the expression stack. |
| 309 Label loop, entry; | 308 Label loop, entry; |
| 310 __ movp(rcx, rax); | 309 __ movp(rcx, rax); |
| 311 __ jmp(&entry); | 310 __ jmp(&entry); |
| 312 __ bind(&loop); | 311 __ bind(&loop); |
| 313 __ Push(Operand(rbx, rcx, times_pointer_size, 0)); | 312 __ Push(Operand(rbx, rcx, times_pointer_size, 0)); |
| 314 __ bind(&entry); | 313 __ bind(&entry); |
| 315 __ decp(rcx); | 314 __ decp(rcx); |
| 316 __ j(greater_equal, &loop); | 315 __ j(greater_equal, &loop); |
| 317 | 316 |
| 318 // Call the function. | 317 // Call the function. |
| 319 if (is_api_function) { | 318 if (is_api_function) { |
| 320 __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); | 319 __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
| 321 Handle<Code> code = | 320 Handle<Code> code = |
| 322 masm->isolate()->builtins()->HandleApiCallConstruct(); | 321 masm->isolate()->builtins()->HandleApiCallConstruct(); |
| 323 __ Call(code, RelocInfo::CODE_TARGET); | 322 __ Call(code, RelocInfo::CODE_TARGET); |
| 324 } else { | 323 } else { |
| 325 ParameterCount actual(rax); | 324 ParameterCount actual(rax); |
| 326 __ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper()); | 325 __ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper()); |
| 327 } | 326 } |
| 328 | 327 |
| 329 // Store offset of return address for deoptimizer. | 328 // Store offset of return address for deoptimizer. |
| 330 if (!is_api_function) { | 329 if (create_implicit_receiver && !is_api_function) { |
| 331 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); | 330 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); |
| 332 } | 331 } |
| 333 | 332 |
| 334 // Restore context from the frame. | 333 // Restore context from the frame. |
| 335 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 334 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 336 | 335 |
| 337 // If the result is an object (in the ECMA sense), we should get rid | 336 if (create_implicit_receiver) { |
| 338 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 | 337 // If the result is an object (in the ECMA sense), we should get rid |
| 339 // on page 74. | 338 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 |
| 340 Label use_receiver, exit; | 339 // on page 74. |
| 341 // If the result is a smi, it is *not* an object in the ECMA sense. | 340 Label use_receiver, exit; |
| 342 __ JumpIfSmi(rax, &use_receiver); | 341 // If the result is a smi, it is *not* an object in the ECMA sense. |
| 342 __ JumpIfSmi(rax, &use_receiver); |
| 343 | 343 |
| 344 // If the type of the result (stored in its map) is less than | 344 // If the type of the result (stored in its map) is less than |
| 345 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. | 345 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. |
| 346 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); | 346 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); |
| 347 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); | 347 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); |
| 348 __ j(above_equal, &exit); | 348 __ j(above_equal, &exit); |
| 349 | 349 |
| 350 // Throw away the result of the constructor invocation and use the | 350 // Throw away the result of the constructor invocation and use the |
| 351 // on-stack receiver as the result. | 351 // on-stack receiver as the result. |
| 352 __ bind(&use_receiver); | 352 __ bind(&use_receiver); |
| 353 __ movp(rax, Operand(rsp, 0)); | 353 __ movp(rax, Operand(rsp, 0)); |
| 354 | 354 |
| 355 // Restore the arguments count and leave the construct frame. The arguments | 355 // Restore the arguments count and leave the construct frame. The |
| 356 // count is stored below the reciever and the new.target. | 356 // arguments count is stored below the reciever and the new.target. |
| 357 __ bind(&exit); | 357 __ bind(&exit); |
| 358 __ movp(rbx, Operand(rsp, 2 * kPointerSize)); | 358 __ movp(rbx, Operand(rsp, 2 * kPointerSize)); |
| 359 } else { |
| 360 __ movp(rbx, Operand(rsp, kPointerSize)); |
| 361 } |
| 359 | 362 |
| 360 // Leave construct frame. | 363 // Leave construct frame. |
| 361 } | 364 } |
| 362 | 365 |
| 363 // Remove caller arguments from the stack and return. | 366 // Remove caller arguments from the stack and return. |
| 364 __ PopReturnAddressTo(rcx); | 367 __ PopReturnAddressTo(rcx); |
| 365 SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2); | 368 SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2); |
| 366 __ leap(rsp, Operand(rsp, index.reg, index.scale, 1 * kPointerSize)); | 369 __ leap(rsp, Operand(rsp, index.reg, index.scale, 1 * kPointerSize)); |
| 367 __ PushReturnAddressFrom(rcx); | 370 __ PushReturnAddressFrom(rcx); |
| 368 Counters* counters = masm->isolate()->counters(); | 371 if (create_implicit_receiver) { |
| 369 __ IncrementCounter(counters->constructed_objects(), 1); | 372 Counters* counters = masm->isolate()->counters(); |
| 373 __ IncrementCounter(counters->constructed_objects(), 1); |
| 374 } |
| 370 __ ret(0); | 375 __ ret(0); |
| 371 } | 376 } |
| 372 | 377 |
| 373 | 378 |
| 374 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { | 379 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { |
| 375 Generate_JSConstructStubHelper(masm, false); | 380 Generate_JSConstructStubHelper(masm, false, true); |
| 376 } | 381 } |
| 377 | 382 |
| 378 | 383 |
| 379 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { | 384 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { |
| 380 Generate_JSConstructStubHelper(masm, true); | 385 Generate_JSConstructStubHelper(masm, true, true); |
| 381 } | 386 } |
| 382 | 387 |
| 383 | 388 |
| 384 void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) { | 389 void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) { |
| 385 // ----------- S t a t e ------------- | 390 Generate_JSConstructStubHelper(masm, false, false); |
| 386 // -- rax: number of arguments | |
| 387 // -- rdi: constructor function | |
| 388 // -- rbx: allocation site or undefined | |
| 389 // -- rdx: new target | |
| 390 // ----------------------------------- | |
| 391 | |
| 392 { | |
| 393 FrameScope frame_scope(masm, StackFrame::CONSTRUCT); | |
| 394 | |
| 395 // Preserve allocation site. | |
| 396 __ AssertUndefinedOrAllocationSite(rbx); | |
| 397 __ Push(rbx); | |
| 398 | |
| 399 // Store a smi-tagged arguments count on the stack. | |
| 400 __ Integer32ToSmi(rax, rax); | |
| 401 __ Push(rax); | |
| 402 __ SmiToInteger32(rax, rax); | |
| 403 | |
| 404 // Push new.target | |
| 405 __ Push(rdx); | |
| 406 | |
| 407 // receiver is the hole. | |
| 408 __ Push(masm->isolate()->factory()->the_hole_value()); | |
| 409 | |
| 410 // Set up pointer to last argument. | |
| 411 __ leap(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset)); | |
| 412 | |
| 413 // Copy arguments and receiver to the expression stack. | |
| 414 Label loop, entry; | |
| 415 __ movp(rcx, rax); | |
| 416 __ jmp(&entry); | |
| 417 __ bind(&loop); | |
| 418 __ Push(Operand(rbx, rcx, times_pointer_size, 0)); | |
| 419 __ bind(&entry); | |
| 420 __ decp(rcx); | |
| 421 __ j(greater_equal, &loop); | |
| 422 | |
| 423 // Call the function. | |
| 424 ParameterCount actual(rax); | |
| 425 __ InvokeFunction(rdi, actual, CALL_FUNCTION, NullCallWrapper()); | |
| 426 | |
| 427 // Restore context from the frame. | |
| 428 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | |
| 429 | |
| 430 // Get arguments count, skipping over new.target. | |
| 431 __ movp(rbx, Operand(rsp, kPointerSize)); // Get arguments count. | |
| 432 } // Leave construct frame. | |
| 433 | |
| 434 // Remove caller arguments from the stack and return. | |
| 435 __ PopReturnAddressTo(rcx); | |
| 436 SmiIndex index = masm->SmiToIndex(rbx, rbx, kPointerSizeLog2); | |
| 437 __ leap(rsp, Operand(rsp, index.reg, index.scale, 1 * kPointerSize)); | |
| 438 __ PushReturnAddressFrom(rcx); | |
| 439 __ ret(0); | |
| 440 } | 391 } |
| 441 | 392 |
| 442 | 393 |
| 443 enum IsTagged { kRaxIsSmiTagged, kRaxIsUntaggedInt }; | 394 enum IsTagged { kRaxIsSmiTagged, kRaxIsUntaggedInt }; |
| 444 | 395 |
| 445 | 396 |
| 446 // Clobbers rcx, r11, kScratchRegister; preserves all other registers. | 397 // Clobbers rcx, r11, kScratchRegister; preserves all other registers. |
| 447 static void Generate_CheckStackOverflow(MacroAssembler* masm, | 398 static void Generate_CheckStackOverflow(MacroAssembler* masm, |
| 448 IsTagged rax_is_tagged) { | 399 IsTagged rax_is_tagged) { |
| 449 // rax : the number of items to be pushed to the stack | 400 // rax : the number of items to be pushed to the stack |
| (...skipping 1528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1978 __ ret(0); | 1929 __ ret(0); |
| 1979 } | 1930 } |
| 1980 | 1931 |
| 1981 | 1932 |
| 1982 #undef __ | 1933 #undef __ |
| 1983 | 1934 |
| 1984 } // namespace internal | 1935 } // namespace internal |
| 1985 } // namespace v8 | 1936 } // namespace v8 |
| 1986 | 1937 |
| 1987 #endif // V8_TARGET_ARCH_X64 | 1938 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |