Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: src/ia32/builtins-ia32.cc

Issue 1221803004: Unify all four JSConstructStub generators into one. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@local_graph-builder-super-1
Patch Set: Rebased. Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #if V8_TARGET_ARCH_IA32 7 #if V8_TARGET_ARCH_IA32
8 8
9 #include "src/code-factory.h" 9 #include "src/code-factory.h"
10 #include "src/codegen.h" 10 #include "src/codegen.h"
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 __ jmp(count_incremented); 132 __ jmp(count_incremented);
133 } else { 133 } else {
134 __ jmp(allocated); 134 __ jmp(allocated);
135 } 135 }
136 } 136 }
137 137
138 138
139 static void Generate_JSConstructStubHelper(MacroAssembler* masm, 139 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
140 bool is_api_function, 140 bool is_api_function,
141 bool use_new_target, 141 bool use_new_target,
142 bool is_derived_class,
142 bool create_memento) { 143 bool create_memento) {
143 // ----------- S t a t e ------------- 144 // ----------- S t a t e -------------
144 // -- eax: number of arguments 145 // -- eax: number of arguments
145 // -- edi: constructor function 146 // -- edi: constructor function
146 // -- ebx: allocation site or undefined 147 // -- ebx: allocation site or undefined
147 // -- edx: original constructor 148 // -- edx: original constructor
148 // ----------------------------------- 149 // -----------------------------------
149 150
150 // Should never create mementos for api functions. 151 // Should never create mementos for api functions.
151 DCHECK(!is_api_function || !create_memento); 152 DCHECK(!is_api_function || !create_memento);
152 153
154 // Should never create mementos for subclass constructors.
155 DCHECK(!is_derived_class || !create_memento);
156
153 // Enter a construct frame. 157 // Enter a construct frame.
154 { 158 {
155 FrameScope scope(masm, StackFrame::CONSTRUCT); 159 FrameScope scope(masm, StackFrame::CONSTRUCT);
156 160
157 if (create_memento) { 161 if (create_memento) {
158 __ AssertUndefinedOrAllocationSite(ebx); 162 __ AssertUndefinedOrAllocationSite(ebx);
159 __ push(ebx); 163 __ push(ebx);
160 } 164 }
161 165
162 // Preserve the incoming parameters on the stack. 166 // Preserve the incoming parameters on the stack.
163 __ SmiTag(eax); 167 __ SmiTag(eax);
164 __ push(eax); 168 __ push(eax);
165 __ push(edi); 169 if (!is_derived_class) {
166 if (use_new_target) { 170 __ push(edi);
167 __ push(edx); 171 if (use_new_target) {
172 __ push(edx);
173 }
174
175 __ cmp(edx, edi);
176 Label normal_new;
177 Label count_incremented;
178 Label allocated;
179 __ j(equal, &normal_new);
180
181 // Original constructor and function are different.
182 Generate_Runtime_NewObject(masm, create_memento, edx, &count_incremented,
183 &allocated);
184 __ bind(&normal_new);
185
186 // Try to allocate the object without transitioning into C code. If any of
187 // the preconditions is not met, the code bails out to the runtime call.
188 Label rt_call;
189 if (FLAG_inline_new) {
190 Label undo_allocation;
191 ExternalReference debug_step_in_fp =
192 ExternalReference::debug_step_in_fp_address(masm->isolate());
193 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
194 __ j(not_equal, &rt_call);
195
196 // Verified that the constructor is a JSFunction.
197 // Load the initial map and verify that it is in fact a map.
198 // edi: constructor
199 __ mov(eax,
200 FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
201 // Will both indicate a NULL and a Smi
202 __ JumpIfSmi(eax, &rt_call);
203 // edi: constructor
204 // eax: initial map (if proven valid below)
205 __ CmpObjectType(eax, MAP_TYPE, ebx);
206 __ j(not_equal, &rt_call);
207
208 // Check that the constructor is not constructing a JSFunction (see
209 // comments in Runtime_NewObject in runtime.cc). In which case the
210 // initial map's instance type would be JS_FUNCTION_TYPE.
211 // edi: constructor
212 // eax: initial map
213 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
214 __ j(equal, &rt_call);
215
216 if (!is_api_function) {
217 Label allocate;
218 // The code below relies on these assumptions.
219 STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32);
220 // Check if slack tracking is enabled.
221 __ mov(esi, FieldOperand(eax, Map::kBitField3Offset));
222 __ shr(esi, Map::Counter::kShift);
223 __ cmp(esi, Map::kSlackTrackingCounterEnd);
224 __ j(less, &allocate);
225 // Decrease generous allocation count.
226 __ sub(FieldOperand(eax, Map::kBitField3Offset),
227 Immediate(1 << Map::Counter::kShift));
228
229 __ cmp(esi, Map::kSlackTrackingCounterEnd);
230 __ j(not_equal, &allocate);
231
232 __ push(eax);
233 __ push(edi);
234
235 __ push(edi); // constructor
236 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
237
238 __ pop(edi);
239 __ pop(eax);
240 __ mov(esi, Map::kSlackTrackingCounterEnd - 1);
241
242 __ bind(&allocate);
243 }
244
245 // Now allocate the JSObject on the heap.
246 // edi: constructor
247 // eax: initial map
248 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
249 __ shl(edi, kPointerSizeLog2);
250 if (create_memento) {
251 __ add(edi, Immediate(AllocationMemento::kSize));
252 }
253
254 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
255
256 Factory* factory = masm->isolate()->factory();
257
258 // Allocated the JSObject, now initialize the fields.
259 // eax: initial map
260 // ebx: JSObject
261 // edi: start of next object (including memento if create_memento)
262 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
263 __ mov(ecx, factory->empty_fixed_array());
264 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
265 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
266 // Set extra fields in the newly allocated object.
267 // eax: initial map
268 // ebx: JSObject
269 // edi: start of next object (including memento if create_memento)
270 // esi: slack tracking counter (non-API function case)
271 __ mov(edx, factory->undefined_value());
272 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
273 if (!is_api_function) {
274 Label no_inobject_slack_tracking;
275
276 // Check if slack tracking is enabled.
277 __ cmp(esi, Map::kSlackTrackingCounterEnd);
278 __ j(less, &no_inobject_slack_tracking);
279
280 // Allocate object with a slack.
281 __ movzx_b(esi,
282 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
283 __ lea(esi,
284 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize));
285 // esi: offset of first field after pre-allocated fields
286 if (FLAG_debug_code) {
287 __ cmp(esi, edi);
288 __ Assert(less_equal,
289 kUnexpectedNumberOfPreAllocatedPropertyFields);
290 }
291 __ InitializeFieldsWithFiller(ecx, esi, edx);
292 __ mov(edx, factory->one_pointer_filler_map());
293 // Fill the remaining fields with one pointer filler map.
294
295 __ bind(&no_inobject_slack_tracking);
296 }
297
298 if (create_memento) {
299 __ lea(esi, Operand(edi, -AllocationMemento::kSize));
300 __ InitializeFieldsWithFiller(ecx, esi, edx);
301
302 // Fill in memento fields if necessary.
303 // esi: points to the allocated but uninitialized memento.
304 __ mov(Operand(esi, AllocationMemento::kMapOffset),
305 factory->allocation_memento_map());
306 // Get the cell or undefined.
307 __ mov(edx, Operand(esp, kPointerSize * 2));
308 __ mov(Operand(esi, AllocationMemento::kAllocationSiteOffset), edx);
309 } else {
310 __ InitializeFieldsWithFiller(ecx, edi, edx);
311 }
312
313 // Add the object tag to make the JSObject real, so that we can continue
314 // and jump into the continuation code at any time from now on. Any
315 // failures need to undo the allocation, so that the heap is in a
316 // consistent state and verifiable.
317 // eax: initial map
318 // ebx: JSObject
319 // edi: start of next object
320 __ or_(ebx, Immediate(kHeapObjectTag));
321
322 // Check if a non-empty properties array is needed.
323 // Allocate and initialize a FixedArray if it is.
324 // eax: initial map
325 // ebx: JSObject
326 // edi: start of next object
327 // Calculate the total number of properties described by the map.
328 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
329 __ movzx_b(ecx,
330 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
331 __ add(edx, ecx);
332 // Calculate unused properties past the end of the in-object properties.
333 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
334 __ sub(edx, ecx);
335 // Done if no extra properties are to be allocated.
336 __ j(zero, &allocated);
337 __ Assert(positive, kPropertyAllocationCountFailed);
338
339 // Scale the number of elements by pointer size and add the header for
340 // FixedArrays to the start of the next object calculation from above.
341 // ebx: JSObject
342 // edi: start of next object (will be start of FixedArray)
343 // edx: number of elements in properties array
344 __ Allocate(FixedArray::kHeaderSize, times_pointer_size, edx,
345 REGISTER_VALUE_IS_INT32, edi, ecx, no_reg, &undo_allocation,
346 RESULT_CONTAINS_TOP);
347
348 // Initialize the FixedArray.
349 // ebx: JSObject
350 // edi: FixedArray
351 // edx: number of elements
352 // ecx: start of next object
353 __ mov(eax, factory->fixed_array_map());
354 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
355 __ SmiTag(edx);
356 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
357
358 // Initialize the fields to undefined.
359 // ebx: JSObject
360 // edi: FixedArray
361 // ecx: start of next object
362 __ mov(edx, factory->undefined_value());
363 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
364 __ InitializeFieldsWithFiller(eax, ecx, edx);
365
366 // Store the initialized FixedArray into the properties field of
367 // the JSObject
368 // ebx: JSObject
369 // edi: FixedArray
370 __ or_(edi, Immediate(kHeapObjectTag)); // add the heap tag
371 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
372
373
374 // Continue with JSObject being successfully allocated
375 // ebx: JSObject
376 __ jmp(&allocated);
377
378 // Undo the setting of the new top so that the heap is verifiable. For
379 // example, the map's unused properties potentially do not match the
380 // allocated objects unused properties.
381 // ebx: JSObject (previous new top)
382 __ bind(&undo_allocation);
383 __ UndoAllocationInNewSpace(ebx);
384 }
385
386 // Allocate the new receiver object using the runtime call.
387 __ bind(&rt_call);
388 Generate_Runtime_NewObject(masm, create_memento, edi, &count_incremented,
389 &allocated);
390 // New object allocated.
391 // ebx: newly allocated object
392 __ bind(&allocated);
393
394 if (create_memento) {
395 int offset = (use_new_target ? 3 : 2) * kPointerSize;
396 __ mov(ecx, Operand(esp, offset));
397 __ cmp(ecx, masm->isolate()->factory()->undefined_value());
398 __ j(equal, &count_incremented);
399 // ecx is an AllocationSite. We are creating a memento from it, so we
400 // need to increment the memento create count.
401 __ add(FieldOperand(ecx, AllocationSite::kPretenureCreateCountOffset),
402 Immediate(Smi::FromInt(1)));
403 __ bind(&count_incremented);
404 }
405
406 // Restore the parameters.
407 if (use_new_target) {
408 __ pop(edx); // new.target
409 }
410 __ pop(edi); // Constructor function.
411
412 // Retrieve smi-tagged arguments count from the stack.
413 __ mov(eax, Operand(esp, 0));
168 } 414 }
169
170 __ cmp(edx, edi);
171 Label normal_new;
172 Label count_incremented;
173 Label allocated;
174 __ j(equal, &normal_new);
175
176 // Original constructor and function are different.
177 Generate_Runtime_NewObject(masm, create_memento, edx, &count_incremented,
178 &allocated);
179 __ bind(&normal_new);
180
181 // Try to allocate the object without transitioning into C code. If any of
182 // the preconditions is not met, the code bails out to the runtime call.
183 Label rt_call;
184 if (FLAG_inline_new) {
185 Label undo_allocation;
186 ExternalReference debug_step_in_fp =
187 ExternalReference::debug_step_in_fp_address(masm->isolate());
188 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
189 __ j(not_equal, &rt_call);
190
191 // Verified that the constructor is a JSFunction.
192 // Load the initial map and verify that it is in fact a map.
193 // edi: constructor
194 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset));
195 // Will both indicate a NULL and a Smi
196 __ JumpIfSmi(eax, &rt_call);
197 // edi: constructor
198 // eax: initial map (if proven valid below)
199 __ CmpObjectType(eax, MAP_TYPE, ebx);
200 __ j(not_equal, &rt_call);
201
202 // Check that the constructor is not constructing a JSFunction (see
203 // comments in Runtime_NewObject in runtime.cc). In which case the
204 // initial map's instance type would be JS_FUNCTION_TYPE.
205 // edi: constructor
206 // eax: initial map
207 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
208 __ j(equal, &rt_call);
209
210 if (!is_api_function) {
211 Label allocate;
212 // The code below relies on these assumptions.
213 STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32);
214 // Check if slack tracking is enabled.
215 __ mov(esi, FieldOperand(eax, Map::kBitField3Offset));
216 __ shr(esi, Map::Counter::kShift);
217 __ cmp(esi, Map::kSlackTrackingCounterEnd);
218 __ j(less, &allocate);
219 // Decrease generous allocation count.
220 __ sub(FieldOperand(eax, Map::kBitField3Offset),
221 Immediate(1 << Map::Counter::kShift));
222
223 __ cmp(esi, Map::kSlackTrackingCounterEnd);
224 __ j(not_equal, &allocate);
225
226 __ push(eax);
227 __ push(edi);
228
229 __ push(edi); // constructor
230 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
231
232 __ pop(edi);
233 __ pop(eax);
234 __ mov(esi, Map::kSlackTrackingCounterEnd - 1);
235
236 __ bind(&allocate);
237 }
238
239 // Now allocate the JSObject on the heap.
240 // edi: constructor
241 // eax: initial map
242 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset));
243 __ shl(edi, kPointerSizeLog2);
244 if (create_memento) {
245 __ add(edi, Immediate(AllocationMemento::kSize));
246 }
247
248 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS);
249
250 Factory* factory = masm->isolate()->factory();
251
252 // Allocated the JSObject, now initialize the fields.
253 // eax: initial map
254 // ebx: JSObject
255 // edi: start of next object (including memento if create_memento)
256 __ mov(Operand(ebx, JSObject::kMapOffset), eax);
257 __ mov(ecx, factory->empty_fixed_array());
258 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx);
259 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx);
260 // Set extra fields in the newly allocated object.
261 // eax: initial map
262 // ebx: JSObject
263 // edi: start of next object (including memento if create_memento)
264 // esi: slack tracking counter (non-API function case)
265 __ mov(edx, factory->undefined_value());
266 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize));
267 if (!is_api_function) {
268 Label no_inobject_slack_tracking;
269
270 // Check if slack tracking is enabled.
271 __ cmp(esi, Map::kSlackTrackingCounterEnd);
272 __ j(less, &no_inobject_slack_tracking);
273
274 // Allocate object with a slack.
275 __ movzx_b(esi,
276 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
277 __ lea(esi,
278 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize));
279 // esi: offset of first field after pre-allocated fields
280 if (FLAG_debug_code) {
281 __ cmp(esi, edi);
282 __ Assert(less_equal,
283 kUnexpectedNumberOfPreAllocatedPropertyFields);
284 }
285 __ InitializeFieldsWithFiller(ecx, esi, edx);
286 __ mov(edx, factory->one_pointer_filler_map());
287 // Fill the remaining fields with one pointer filler map.
288
289 __ bind(&no_inobject_slack_tracking);
290 }
291
292 if (create_memento) {
293 __ lea(esi, Operand(edi, -AllocationMemento::kSize));
294 __ InitializeFieldsWithFiller(ecx, esi, edx);
295
296 // Fill in memento fields if necessary.
297 // esi: points to the allocated but uninitialized memento.
298 __ mov(Operand(esi, AllocationMemento::kMapOffset),
299 factory->allocation_memento_map());
300 // Get the cell or undefined.
301 __ mov(edx, Operand(esp, kPointerSize*2));
302 __ mov(Operand(esi, AllocationMemento::kAllocationSiteOffset),
303 edx);
304 } else {
305 __ InitializeFieldsWithFiller(ecx, edi, edx);
306 }
307
308 // Add the object tag to make the JSObject real, so that we can continue
309 // and jump into the continuation code at any time from now on. Any
310 // failures need to undo the allocation, so that the heap is in a
311 // consistent state and verifiable.
312 // eax: initial map
313 // ebx: JSObject
314 // edi: start of next object
315 __ or_(ebx, Immediate(kHeapObjectTag));
316
317 // Check if a non-empty properties array is needed.
318 // Allocate and initialize a FixedArray if it is.
319 // eax: initial map
320 // ebx: JSObject
321 // edi: start of next object
322 // Calculate the total number of properties described by the map.
323 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset));
324 __ movzx_b(ecx,
325 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset));
326 __ add(edx, ecx);
327 // Calculate unused properties past the end of the in-object properties.
328 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset));
329 __ sub(edx, ecx);
330 // Done if no extra properties are to be allocated.
331 __ j(zero, &allocated);
332 __ Assert(positive, kPropertyAllocationCountFailed);
333
334 // Scale the number of elements by pointer size and add the header for
335 // FixedArrays to the start of the next object calculation from above.
336 // ebx: JSObject
337 // edi: start of next object (will be start of FixedArray)
338 // edx: number of elements in properties array
339 __ Allocate(FixedArray::kHeaderSize,
340 times_pointer_size,
341 edx,
342 REGISTER_VALUE_IS_INT32,
343 edi,
344 ecx,
345 no_reg,
346 &undo_allocation,
347 RESULT_CONTAINS_TOP);
348
349 // Initialize the FixedArray.
350 // ebx: JSObject
351 // edi: FixedArray
352 // edx: number of elements
353 // ecx: start of next object
354 __ mov(eax, factory->fixed_array_map());
355 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map
356 __ SmiTag(edx);
357 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length
358
359 // Initialize the fields to undefined.
360 // ebx: JSObject
361 // edi: FixedArray
362 // ecx: start of next object
363 __ mov(edx, factory->undefined_value());
364 __ lea(eax, Operand(edi, FixedArray::kHeaderSize));
365 __ InitializeFieldsWithFiller(eax, ecx, edx);
366
367 // Store the initialized FixedArray into the properties field of
368 // the JSObject
369 // ebx: JSObject
370 // edi: FixedArray
371 __ or_(edi, Immediate(kHeapObjectTag)); // add the heap tag
372 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi);
373
374
375 // Continue with JSObject being successfully allocated
376 // ebx: JSObject
377 __ jmp(&allocated);
378
379 // Undo the setting of the new top so that the heap is verifiable. For
380 // example, the map's unused properties potentially do not match the
381 // allocated objects unused properties.
382 // ebx: JSObject (previous new top)
383 __ bind(&undo_allocation);
384 __ UndoAllocationInNewSpace(ebx);
385 }
386
387 // Allocate the new receiver object using the runtime call.
388 __ bind(&rt_call);
389 Generate_Runtime_NewObject(masm, create_memento, edi, &count_incremented,
390 &allocated);
391 // New object allocated.
392 // ebx: newly allocated object
393 __ bind(&allocated);
394
395 if (create_memento) {
396 int offset = (use_new_target ? 3 : 2) * kPointerSize;
397 __ mov(ecx, Operand(esp, offset));
398 __ cmp(ecx, masm->isolate()->factory()->undefined_value());
399 __ j(equal, &count_incremented);
400 // ecx is an AllocationSite. We are creating a memento from it, so we
401 // need to increment the memento create count.
402 __ add(FieldOperand(ecx, AllocationSite::kPretenureCreateCountOffset),
403 Immediate(Smi::FromInt(1)));
404 __ bind(&count_incremented);
405 }
406
407 // Restore the parameters.
408 if (use_new_target) {
409 __ pop(edx); // new.target
410 }
411 __ pop(edi); // Constructor function.
412
413 // Retrieve smi-tagged arguments count from the stack.
414 __ mov(eax, Operand(esp, 0));
415 __ SmiUntag(eax); 415 __ SmiUntag(eax);
416 416
417 // Push new.target onto the construct frame. This is stored just below the 417 // Push new.target onto the construct frame. This is stored just below the
418 // receiver on the stack. 418 // receiver on the stack.
419 if (use_new_target) { 419 if (use_new_target) {
420 __ push(edx); 420 __ push(edx);
421 } 421 }
422 422
423 // Push the allocated receiver to the stack. We need two copies 423 // Push the allocated receiver to the stack. We need two copies
424 // because we may have to return the original one and the calling 424 // because we may have to return the original one and the calling
425 // conventions dictate that the called function pops the receiver. 425 // conventions dictate that the called function pops the receiver.
426 __ push(ebx); 426 if (!is_derived_class) {
427 __ push(ebx); 427 __ push(ebx);
428 __ push(ebx);
429 } else {
430 // receiver is the hole.
431 __ push(Immediate(masm->isolate()->factory()->the_hole_value()));
432 }
428 433
429 // Set up pointer to last argument. 434 // Set up pointer to last argument.
430 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); 435 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
431 436
432 // Copy arguments and receiver to the expression stack. 437 // Copy arguments and receiver to the expression stack.
433 Label loop, entry; 438 Label loop, entry;
434 __ mov(ecx, eax); 439 __ mov(ecx, eax);
435 __ jmp(&entry); 440 __ jmp(&entry);
436 __ bind(&loop); 441 __ bind(&loop);
437 __ push(Operand(ebx, ecx, times_4, 0)); 442 __ push(Operand(ebx, ecx, times_4, 0));
438 __ bind(&entry); 443 __ bind(&entry);
439 __ dec(ecx); 444 __ dec(ecx);
440 __ j(greater_equal, &loop); 445 __ j(greater_equal, &loop);
441 446
447 // Handle step in.
448 if (is_derived_class) {
449 Label skip_step_in;
450 ExternalReference debug_step_in_fp =
451 ExternalReference::debug_step_in_fp_address(masm->isolate());
452 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
453 __ j(equal, &skip_step_in);
454
455 __ push(eax);
456 __ push(edi);
457 __ push(edi);
458 __ CallRuntime(Runtime::kHandleStepInForDerivedConstructors, 1);
459 __ pop(edi);
460 __ pop(eax);
461
462 __ bind(&skip_step_in);
463 }
464
442 // Call the function. 465 // Call the function.
443 if (is_api_function) { 466 if (is_api_function) {
444 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 467 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
445 Handle<Code> code = 468 Handle<Code> code =
446 masm->isolate()->builtins()->HandleApiCallConstruct(); 469 masm->isolate()->builtins()->HandleApiCallConstruct();
447 __ call(code, RelocInfo::CODE_TARGET); 470 __ call(code, RelocInfo::CODE_TARGET);
448 } else { 471 } else {
449 ParameterCount actual(eax); 472 ParameterCount actual(eax);
450 __ InvokeFunction(edi, actual, CALL_FUNCTION, 473 __ InvokeFunction(edi, actual, CALL_FUNCTION,
451 NullCallWrapper()); 474 NullCallWrapper());
452 } 475 }
453 476
454 // Store offset of return address for deoptimizer. 477 // Store offset of return address for deoptimizer.
455 // TODO(arv): Remove the "!use_new_target" before supporting optimization 478 // TODO(arv): Remove the "!use_new_target" before supporting optimization
456 // of functions that reference new.target 479 // of functions that reference new.target
457 if (!is_api_function && !use_new_target) { 480 if (!is_api_function && !use_new_target && !is_derived_class) {
458 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); 481 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
459 } 482 }
460 483
461 // Restore context from the frame. 484 // Restore context from the frame.
462 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 485 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
463 486
464 // If the result is an object (in the ECMA sense), we should get rid 487 // If the result is an object (in the ECMA sense), we should get rid
465 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 488 // of the receiver and use the result; see ECMA-262 section 13.2.2-7
466 // on page 74. 489 // on page 74.
467 Label use_receiver, exit; 490 if (!is_derived_class) {
491 Label use_receiver, exit;
468 492
469 // If the result is a smi, it is *not* an object in the ECMA sense. 493 // If the result is a smi, it is *not* an object in the ECMA sense.
470 __ JumpIfSmi(eax, &use_receiver); 494 __ JumpIfSmi(eax, &use_receiver);
471 495
472 // If the type of the result (stored in its map) is less than 496 // If the type of the result (stored in its map) is less than
473 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. 497 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
474 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 498 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
475 __ j(above_equal, &exit); 499 __ j(above_equal, &exit);
476 500
477 // Throw away the result of the constructor invocation and use the 501 // Throw away the result of the constructor invocation and use the
478 // on-stack receiver as the result. 502 // on-stack receiver as the result.
479 __ bind(&use_receiver); 503 __ bind(&use_receiver);
480 __ mov(eax, Operand(esp, 0)); 504 __ mov(eax, Operand(esp, 0));
505
506 __ bind(&exit);
507 }
481 508
482 // Restore the arguments count and leave the construct frame. The arguments 509 // Restore the arguments count and leave the construct frame. The arguments
483 // count is stored below the reciever and the new.target. 510 // count is stored below the reciever and the new.target.
484 __ bind(&exit); 511 int offset = ((use_new_target && !is_derived_class) ? 2 : 1) * kPointerSize;
485 int offset = (use_new_target ? 2 : 1) * kPointerSize;
486 __ mov(ebx, Operand(esp, offset)); 512 __ mov(ebx, Operand(esp, offset));
487 513
488 // Leave construct frame. 514 // Leave construct frame.
489 } 515 }
490 516
491 // Remove caller arguments from the stack and return. 517 // Remove caller arguments from the stack and return.
492 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 518 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
493 __ pop(ecx); 519 __ pop(ecx);
494 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver 520 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver
495 __ push(ecx); 521 __ push(ecx);
496 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); 522 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1);
497 __ ret(0); 523 __ ret(0);
498 } 524 }
499 525
500 526
501 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { 527 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
502 Generate_JSConstructStubHelper(masm, false, false, FLAG_pretenuring_call_new); 528 bool create_memento = FLAG_pretenuring_call_new;
529 Generate_JSConstructStubHelper(masm, false, false, false, create_memento);
503 } 530 }
504 531
505 532
506 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { 533 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
507 Generate_JSConstructStubHelper(masm, true, false, false); 534 Generate_JSConstructStubHelper(masm, true, false, false, false);
508 } 535 }
509 536
510 537
511 void Builtins::Generate_JSConstructStubNewTarget(MacroAssembler* masm) { 538 void Builtins::Generate_JSConstructStubNewTarget(MacroAssembler* masm) {
arv (Not doing code reviews) 2015/07/07 16:32:26 I think we should get rid of this stub and have JS
Michael Starzinger 2015/07/07 16:46:59 Yes, oh god please yes, from the bottom of my hear
Michael Starzinger 2015/07/07 16:50:59 To rephrase this in a more professional way: Agree
512 Generate_JSConstructStubHelper(masm, false, true, FLAG_pretenuring_call_new); 539 bool create_memento = FLAG_pretenuring_call_new;
540 Generate_JSConstructStubHelper(masm, false, true, false, create_memento);
513 } 541 }
514 542
515 543
516 void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) { 544 void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) {
517 // ----------- S t a t e ------------- 545 Generate_JSConstructStubHelper(masm, false, true, true, false);
518 // -- eax: number of arguments
519 // -- edi: constructor function
520 // -- ebx: allocation site or undefined
521 // -- edx: original constructor
522 // -----------------------------------
523
524 // TODO(dslomov): support pretenuring
525 CHECK(!FLAG_pretenuring_call_new);
526
527 {
528 FrameScope frame_scope(masm, StackFrame::CONSTRUCT);
529
530 // Preserve actual arguments count.
531 __ SmiTag(eax);
532 __ push(eax);
533 __ SmiUntag(eax);
534
535 // Push new.target.
536 __ push(edx);
537
538 // receiver is the hole.
539 __ push(Immediate(masm->isolate()->factory()->the_hole_value()));
540
541 // Set up pointer to last argument.
542 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset));
543
544 // Copy arguments and receiver to the expression stack.
545 Label loop, entry;
546 __ mov(ecx, eax);
547 __ jmp(&entry);
548 __ bind(&loop);
549 __ push(Operand(ebx, ecx, times_4, 0));
550 __ bind(&entry);
551 __ dec(ecx);
552 __ j(greater_equal, &loop);
553
554 // Handle step in.
555 Label skip_step_in;
556 ExternalReference debug_step_in_fp =
557 ExternalReference::debug_step_in_fp_address(masm->isolate());
558 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0));
559 __ j(equal, &skip_step_in);
560
561 __ push(eax);
562 __ push(edi);
563 __ push(edi);
564 __ CallRuntime(Runtime::kHandleStepInForDerivedConstructors, 1);
565 __ pop(edi);
566 __ pop(eax);
567
568 __ bind(&skip_step_in);
569
570 // Invoke function.
571 ParameterCount actual(eax);
572 __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper());
573
574 // Restore context from the frame.
575 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
576
577 // Get arguments count, skipping over new.target.
578 __ mov(ebx, Operand(esp, kPointerSize));
579 }
580
581 __ pop(ecx); // Return address.
582 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));
583 __ push(ecx);
584 __ ret(0);
585 } 546 }
586 547
587 548
588 enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt }; 549 enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt };
589 550
590 551
591 // Clobbers ecx, edx, edi; preserves all other registers. 552 // Clobbers ecx, edx, edi; preserves all other registers.
592 static void Generate_CheckStackOverflow(MacroAssembler* masm, 553 static void Generate_CheckStackOverflow(MacroAssembler* masm,
593 const int calleeOffset, 554 const int calleeOffset,
594 IsTagged eax_is_tagged) { 555 IsTagged eax_is_tagged) {
(...skipping 1133 matching lines...) Expand 10 before | Expand all | Expand 10 after
1728 1689
1729 __ bind(&ok); 1690 __ bind(&ok);
1730 __ ret(0); 1691 __ ret(0);
1731 } 1692 }
1732 1693
1733 #undef __ 1694 #undef __
1734 } // namespace internal 1695 } // namespace internal
1735 } // namespace v8 1696 } // namespace v8
1736 1697
1737 #endif // V8_TARGET_ARCH_IA32 1698 #endif // V8_TARGET_ARCH_IA32
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698