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