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 #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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |