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