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 "v8.h" | 5 #include "v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_IA32 | 7 #if V8_TARGET_ARCH_IA32 |
8 | 8 |
9 #include "codegen.h" | 9 #include "codegen.h" |
10 #include "deoptimizer.h" | 10 #include "deoptimizer.h" |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 CallRuntimePassFunction(masm, Runtime::kHiddenTryInstallOptimizedCode); | 95 CallRuntimePassFunction(masm, Runtime::kHiddenTryInstallOptimizedCode); |
96 GenerateTailCallToReturnedCode(masm); | 96 GenerateTailCallToReturnedCode(masm); |
97 | 97 |
98 __ bind(&ok); | 98 __ bind(&ok); |
99 GenerateTailCallToSharedCode(masm); | 99 GenerateTailCallToSharedCode(masm); |
100 } | 100 } |
101 | 101 |
102 | 102 |
103 static void Generate_JSConstructStubHelper(MacroAssembler* masm, | 103 static void Generate_JSConstructStubHelper(MacroAssembler* masm, |
104 bool is_api_function, | 104 bool is_api_function, |
105 bool count_constructions, | |
106 bool create_memento) { | 105 bool create_memento) { |
107 // ----------- S t a t e ------------- | 106 // ----------- S t a t e ------------- |
108 // -- eax: number of arguments | 107 // -- eax: number of arguments |
109 // -- edi: constructor function | 108 // -- edi: constructor function |
110 // -- ebx: allocation site or undefined | 109 // -- ebx: allocation site or undefined |
111 // ----------------------------------- | 110 // ----------------------------------- |
112 | 111 |
113 // Should never count constructions for api objects. | |
114 ASSERT(!is_api_function || !count_constructions); | |
115 | |
116 // Should never create mementos for api functions. | 112 // Should never create mementos for api functions. |
117 ASSERT(!is_api_function || !create_memento); | 113 ASSERT(!is_api_function || !create_memento); |
118 | 114 |
119 // Should never create mementos before slack tracking is finished. | |
120 ASSERT(!count_constructions || !create_memento); | |
121 | |
122 // Enter a construct frame. | 115 // Enter a construct frame. |
123 { | 116 { |
124 FrameScope scope(masm, StackFrame::CONSTRUCT); | 117 FrameScope scope(masm, StackFrame::CONSTRUCT); |
125 | 118 |
126 if (create_memento) { | 119 if (create_memento) { |
127 __ AssertUndefinedOrAllocationSite(ebx); | 120 __ AssertUndefinedOrAllocationSite(ebx); |
128 __ push(ebx); | 121 __ push(ebx); |
129 } | 122 } |
130 | 123 |
131 // Store a smi-tagged arguments count on the stack. | 124 // Store a smi-tagged arguments count on the stack. |
(...skipping 25 matching lines...) Expand all Loading... |
157 __ j(not_equal, &rt_call); | 150 __ j(not_equal, &rt_call); |
158 | 151 |
159 // Check that the constructor is not constructing a JSFunction (see | 152 // Check that the constructor is not constructing a JSFunction (see |
160 // comments in Runtime_NewObject in runtime.cc). In which case the | 153 // comments in Runtime_NewObject in runtime.cc). In which case the |
161 // initial map's instance type would be JS_FUNCTION_TYPE. | 154 // initial map's instance type would be JS_FUNCTION_TYPE. |
162 // edi: constructor | 155 // edi: constructor |
163 // eax: initial map | 156 // eax: initial map |
164 __ CmpInstanceType(eax, JS_FUNCTION_TYPE); | 157 __ CmpInstanceType(eax, JS_FUNCTION_TYPE); |
165 __ j(equal, &rt_call); | 158 __ j(equal, &rt_call); |
166 | 159 |
167 if (count_constructions) { | 160 if (!is_api_function) { |
168 Label allocate; | 161 Label allocate; |
| 162 // The code below relies on these assumptions. |
| 163 STATIC_ASSERT(JSFunction::kNoSlackTracking == 0); |
| 164 STATIC_ASSERT(Map::ConstructionCount::kShift + |
| 165 Map::ConstructionCount::kSize == 32); |
| 166 // Check if slack tracking is enabled. |
| 167 __ mov(esi, FieldOperand(eax, Map::kBitField3Offset)); |
| 168 __ shr(esi, Map::ConstructionCount::kShift); |
| 169 __ j(zero, &allocate); // JSFunction::kNoSlackTracking |
169 // Decrease generous allocation count. | 170 // Decrease generous allocation count. |
170 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 171 __ sub(FieldOperand(eax, Map::kBitField3Offset), |
171 __ dec_b(FieldOperand(ecx, | 172 Immediate(1 << Map::ConstructionCount::kShift)); |
172 SharedFunctionInfo::kConstructionCountOffset)); | 173 |
173 __ j(not_zero, &allocate); | 174 __ cmp(esi, JSFunction::kFinishSlackTracking); |
| 175 __ j(not_equal, &allocate); |
174 | 176 |
175 __ push(eax); | 177 __ push(eax); |
176 __ push(edi); | 178 __ push(edi); |
177 | 179 |
178 __ push(edi); // constructor | 180 __ push(edi); // constructor |
179 // The call will replace the stub, so the countdown is only done once. | |
180 __ CallRuntime(Runtime::kHiddenFinalizeInstanceSize, 1); | 181 __ CallRuntime(Runtime::kHiddenFinalizeInstanceSize, 1); |
181 | 182 |
182 __ pop(edi); | 183 __ pop(edi); |
183 __ pop(eax); | 184 __ pop(eax); |
| 185 __ xor_(esi, esi); // JSFunction::kNoSlackTracking |
184 | 186 |
185 __ bind(&allocate); | 187 __ bind(&allocate); |
186 } | 188 } |
187 | 189 |
188 // Now allocate the JSObject on the heap. | 190 // Now allocate the JSObject on the heap. |
189 // edi: constructor | 191 // edi: constructor |
190 // eax: initial map | 192 // eax: initial map |
191 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset)); | 193 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset)); |
192 __ shl(edi, kPointerSizeLog2); | 194 __ shl(edi, kPointerSizeLog2); |
193 if (create_memento) { | 195 if (create_memento) { |
194 __ add(edi, Immediate(AllocationMemento::kSize)); | 196 __ add(edi, Immediate(AllocationMemento::kSize)); |
195 } | 197 } |
196 | 198 |
197 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); | 199 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); |
198 | 200 |
199 Factory* factory = masm->isolate()->factory(); | 201 Factory* factory = masm->isolate()->factory(); |
200 | 202 |
201 // Allocated the JSObject, now initialize the fields. | 203 // Allocated the JSObject, now initialize the fields. |
202 // eax: initial map | 204 // eax: initial map |
203 // ebx: JSObject | 205 // ebx: JSObject |
204 // edi: start of next object (including memento if create_memento) | 206 // edi: start of next object (including memento if create_memento) |
205 __ mov(Operand(ebx, JSObject::kMapOffset), eax); | 207 __ mov(Operand(ebx, JSObject::kMapOffset), eax); |
206 __ mov(ecx, factory->empty_fixed_array()); | 208 __ mov(ecx, factory->empty_fixed_array()); |
207 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx); | 209 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx); |
208 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx); | 210 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx); |
209 // Set extra fields in the newly allocated object. | 211 // Set extra fields in the newly allocated object. |
210 // eax: initial map | 212 // eax: initial map |
211 // ebx: JSObject | 213 // ebx: JSObject |
212 // edi: start of next object (including memento if create_memento) | 214 // edi: start of next object (including memento if create_memento) |
| 215 // esi: slack tracking counter (non-API function case) |
| 216 __ mov(edx, factory->undefined_value()); |
213 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize)); | 217 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize)); |
214 __ mov(edx, factory->undefined_value()); | 218 if (!is_api_function) { |
215 if (count_constructions) { | 219 Label no_inobject_slack_tracking; |
| 220 |
| 221 // Check if slack tracking is enabled. |
| 222 __ cmp(esi, JSFunction::kNoSlackTracking); |
| 223 __ j(equal, &no_inobject_slack_tracking); |
| 224 |
| 225 // Allocate object with a slack. |
216 __ movzx_b(esi, | 226 __ movzx_b(esi, |
217 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset)); | 227 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset)); |
218 __ lea(esi, | 228 __ lea(esi, |
219 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize)); | 229 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize)); |
220 // esi: offset of first field after pre-allocated fields | 230 // esi: offset of first field after pre-allocated fields |
221 if (FLAG_debug_code) { | 231 if (FLAG_debug_code) { |
222 __ cmp(esi, edi); | 232 __ cmp(esi, edi); |
223 __ Assert(less_equal, | 233 __ Assert(less_equal, |
224 kUnexpectedNumberOfPreAllocatedPropertyFields); | 234 kUnexpectedNumberOfPreAllocatedPropertyFields); |
225 } | 235 } |
226 __ InitializeFieldsWithFiller(ecx, esi, edx); | 236 __ InitializeFieldsWithFiller(ecx, esi, edx); |
227 __ mov(edx, factory->one_pointer_filler_map()); | 237 __ mov(edx, factory->one_pointer_filler_map()); |
228 __ InitializeFieldsWithFiller(ecx, edi, edx); | 238 // Fill the remaining fields with one pointer filler map. |
229 } else if (create_memento) { | 239 |
| 240 __ bind(&no_inobject_slack_tracking); |
| 241 } |
| 242 |
| 243 if (create_memento) { |
230 __ lea(esi, Operand(edi, -AllocationMemento::kSize)); | 244 __ lea(esi, Operand(edi, -AllocationMemento::kSize)); |
231 __ InitializeFieldsWithFiller(ecx, esi, edx); | 245 __ InitializeFieldsWithFiller(ecx, esi, edx); |
232 | 246 |
233 // Fill in memento fields if necessary. | 247 // Fill in memento fields if necessary. |
234 // esi: points to the allocated but uninitialized memento. | 248 // esi: points to the allocated but uninitialized memento. |
235 Handle<Map> allocation_memento_map = factory->allocation_memento_map(); | |
236 __ mov(Operand(esi, AllocationMemento::kMapOffset), | 249 __ mov(Operand(esi, AllocationMemento::kMapOffset), |
237 allocation_memento_map); | 250 factory->allocation_memento_map()); |
238 // Get the cell or undefined. | 251 // Get the cell or undefined. |
239 __ mov(edx, Operand(esp, kPointerSize*2)); | 252 __ mov(edx, Operand(esp, kPointerSize*2)); |
240 __ mov(Operand(esi, AllocationMemento::kAllocationSiteOffset), | 253 __ mov(Operand(esi, AllocationMemento::kAllocationSiteOffset), |
241 edx); | 254 edx); |
242 } else { | 255 } else { |
243 __ InitializeFieldsWithFiller(ecx, edi, edx); | 256 __ InitializeFieldsWithFiller(ecx, edi, edx); |
244 } | 257 } |
245 | 258 |
246 // Add the object tag to make the JSObject real, so that we can continue | 259 // Add the object tag to make the JSObject real, so that we can continue |
247 // and jump into the continuation code at any time from now on. Any | 260 // and jump into the continuation code at any time from now on. Any |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
333 // Allocate the new receiver object using the runtime call. | 346 // Allocate the new receiver object using the runtime call. |
334 __ bind(&rt_call); | 347 __ bind(&rt_call); |
335 int offset = 0; | 348 int offset = 0; |
336 if (create_memento) { | 349 if (create_memento) { |
337 // Get the cell or allocation site. | 350 // Get the cell or allocation site. |
338 __ mov(edi, Operand(esp, kPointerSize * 2)); | 351 __ mov(edi, Operand(esp, kPointerSize * 2)); |
339 __ push(edi); | 352 __ push(edi); |
340 offset = kPointerSize; | 353 offset = kPointerSize; |
341 } | 354 } |
342 | 355 |
343 // Must restore edi (constructor) before calling runtime. | 356 // Must restore esi (context) and edi (constructor) before calling runtime. |
| 357 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
344 __ mov(edi, Operand(esp, offset)); | 358 __ mov(edi, Operand(esp, offset)); |
345 // edi: function (constructor) | 359 // edi: function (constructor) |
346 __ push(edi); | 360 __ push(edi); |
347 if (create_memento) { | 361 if (create_memento) { |
348 __ CallRuntime(Runtime::kHiddenNewObjectWithAllocationSite, 2); | 362 __ CallRuntime(Runtime::kHiddenNewObjectWithAllocationSite, 2); |
349 } else { | 363 } else { |
350 __ CallRuntime(Runtime::kHiddenNewObject, 1); | 364 __ CallRuntime(Runtime::kHiddenNewObject, 1); |
351 } | 365 } |
352 __ mov(ebx, eax); // store result in ebx | 366 __ mov(ebx, eax); // store result in ebx |
353 | 367 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 Handle<Code> code = | 420 Handle<Code> code = |
407 masm->isolate()->builtins()->HandleApiCallConstruct(); | 421 masm->isolate()->builtins()->HandleApiCallConstruct(); |
408 __ call(code, RelocInfo::CODE_TARGET); | 422 __ call(code, RelocInfo::CODE_TARGET); |
409 } else { | 423 } else { |
410 ParameterCount actual(eax); | 424 ParameterCount actual(eax); |
411 __ InvokeFunction(edi, actual, CALL_FUNCTION, | 425 __ InvokeFunction(edi, actual, CALL_FUNCTION, |
412 NullCallWrapper()); | 426 NullCallWrapper()); |
413 } | 427 } |
414 | 428 |
415 // Store offset of return address for deoptimizer. | 429 // Store offset of return address for deoptimizer. |
416 if (!is_api_function && !count_constructions) { | 430 if (!is_api_function) { |
417 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); | 431 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); |
418 } | 432 } |
419 | 433 |
420 // Restore context from the frame. | 434 // Restore context from the frame. |
421 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 435 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
422 | 436 |
423 // If the result is an object (in the ECMA sense), we should get rid | 437 // If the result is an object (in the ECMA sense), we should get rid |
424 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 | 438 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 |
425 // on page 74. | 439 // on page 74. |
426 Label use_receiver, exit; | 440 Label use_receiver, exit; |
(...skipping 21 matching lines...) Expand all Loading... |
448 // Remove caller arguments from the stack and return. | 462 // Remove caller arguments from the stack and return. |
449 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 463 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
450 __ pop(ecx); | 464 __ pop(ecx); |
451 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver | 465 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver |
452 __ push(ecx); | 466 __ push(ecx); |
453 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); | 467 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); |
454 __ ret(0); | 468 __ ret(0); |
455 } | 469 } |
456 | 470 |
457 | 471 |
458 void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) { | |
459 Generate_JSConstructStubHelper(masm, false, true, false); | |
460 } | |
461 | |
462 | |
463 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { | 472 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { |
464 Generate_JSConstructStubHelper(masm, false, false, FLAG_pretenuring_call_new); | 473 Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new); |
465 } | 474 } |
466 | 475 |
467 | 476 |
468 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { | 477 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { |
469 Generate_JSConstructStubHelper(masm, true, false, false); | 478 Generate_JSConstructStubHelper(masm, true, false); |
470 } | 479 } |
471 | 480 |
472 | 481 |
473 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, | 482 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
474 bool is_construct) { | 483 bool is_construct) { |
475 ProfileEntryHookStub::MaybeCallEntryHook(masm); | 484 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
476 | 485 |
477 // Clear the context before we push it when entering the internal frame. | 486 // Clear the context before we push it when entering the internal frame. |
478 __ Move(esi, Immediate(0)); | 487 __ Move(esi, Immediate(0)); |
479 | 488 |
(...skipping 954 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1434 | 1443 |
1435 __ bind(&ok); | 1444 __ bind(&ok); |
1436 __ ret(0); | 1445 __ ret(0); |
1437 } | 1446 } |
1438 | 1447 |
1439 #undef __ | 1448 #undef __ |
1440 } | 1449 } |
1441 } // namespace v8::internal | 1450 } // namespace v8::internal |
1442 | 1451 |
1443 #endif // V8_TARGET_ARCH_IA32 | 1452 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |