Chromium Code Reviews| 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) { |
| 161 // esi: slack tracking counter | |
|
Michael Starzinger
2014/05/21 10:42:01
nit: At this point esi does not yet contain the co
Igor Sheludko
2014/05/22 08:05:42
Done.
| |
| 168 Label allocate; | 162 Label allocate; |
| 163 // The code below relies on these assumptions. | |
| 164 STATIC_ASSERT(JSFunction::kNoSlackTracking == 0); | |
| 165 STATIC_ASSERT(Map::ConstructionCount::kShift + | |
| 166 Map::ConstructionCount::kSize == 32); | |
| 167 // Check if slack tracking is enabled. | |
| 168 __ mov(esi, FieldOperand(eax, Map::kBitField3Offset)); | |
| 169 __ shr(esi, Map::ConstructionCount::kShift); | |
| 170 __ j(zero, &allocate); // JSFunction::kNoSlackTracking | |
| 169 // Decrease generous allocation count. | 171 // Decrease generous allocation count. |
| 170 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 172 __ sub(FieldOperand(eax, Map::kBitField3Offset), |
| 171 __ dec_b(FieldOperand(ecx, | 173 Immediate(1 << Map::ConstructionCount::kShift)); |
| 172 SharedFunctionInfo::kConstructionCountOffset)); | 174 |
| 173 __ j(not_zero, &allocate); | 175 __ cmp(esi, JSFunction::kFinishSlackTracking); |
| 176 __ j(not_equal, &allocate); | |
| 174 | 177 |
| 175 __ push(eax); | 178 __ push(eax); |
| 176 __ push(edi); | 179 __ push(edi); |
| 177 | 180 |
| 178 __ push(edi); // constructor | 181 __ push(edi); // constructor |
| 179 // The call will replace the stub, so the countdown is only done once. | |
| 180 __ CallRuntime(Runtime::kHiddenFinalizeInstanceSize, 1); | 182 __ CallRuntime(Runtime::kHiddenFinalizeInstanceSize, 1); |
| 181 | 183 |
| 182 __ pop(edi); | 184 __ pop(edi); |
| 183 __ pop(eax); | 185 __ pop(eax); |
| 186 __ xor_(esi, esi); // JSFunction::kNoSlackTracking | |
| 184 | 187 |
| 185 __ bind(&allocate); | 188 __ bind(&allocate); |
| 186 } | 189 } |
| 187 | 190 |
| 188 // Now allocate the JSObject on the heap. | 191 // Now allocate the JSObject on the heap. |
| 189 // edi: constructor | 192 // edi: constructor |
| 190 // eax: initial map | 193 // eax: initial map |
| 191 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset)); | 194 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset)); |
| 192 __ shl(edi, kPointerSizeLog2); | 195 __ shl(edi, kPointerSizeLog2); |
| 193 if (create_memento) { | 196 if (create_memento) { |
| 194 __ add(edi, Immediate(AllocationMemento::kSize)); | 197 __ add(edi, Immediate(AllocationMemento::kSize)); |
| 195 } | 198 } |
| 196 | 199 |
| 197 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); | 200 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); |
| 198 | 201 |
| 199 Factory* factory = masm->isolate()->factory(); | 202 Factory* factory = masm->isolate()->factory(); |
| 200 | 203 |
| 201 // Allocated the JSObject, now initialize the fields. | 204 // Allocated the JSObject, now initialize the fields. |
| 202 // eax: initial map | 205 // eax: initial map |
| 203 // ebx: JSObject | 206 // ebx: JSObject |
| 204 // edi: start of next object (including memento if create_memento) | 207 // edi: start of next object (including memento if create_memento) |
| 205 __ mov(Operand(ebx, JSObject::kMapOffset), eax); | 208 __ mov(Operand(ebx, JSObject::kMapOffset), eax); |
| 206 __ mov(ecx, factory->empty_fixed_array()); | 209 __ mov(ecx, factory->empty_fixed_array()); |
| 207 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx); | 210 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx); |
| 208 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx); | 211 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx); |
| 209 // Set extra fields in the newly allocated object. | 212 // Set extra fields in the newly allocated object. |
| 210 // eax: initial map | 213 // eax: initial map |
| 211 // ebx: JSObject | 214 // ebx: JSObject |
| 212 // edi: start of next object (including memento if create_memento) | 215 // edi: start of next object (including memento if create_memento) |
| 216 // esi: slack tracking counter (non-API function case) | |
| 217 __ mov(edx, factory->undefined_value()); | |
| 213 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize)); | 218 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize)); |
| 214 __ mov(edx, factory->undefined_value()); | 219 if (is_api_function) { |
| 215 if (count_constructions) { | 220 __ InitializeFieldsWithFiller(ecx, edi, edx); |
| 221 } else { | |
| 222 Label no_inobject_slack_tracking, done_field_initialization; | |
| 223 | |
| 224 // Check if slack tracking is enabled. | |
| 225 __ cmp(esi, JSFunction::kNoSlackTracking); | |
| 226 __ j(equal, &no_inobject_slack_tracking); | |
| 227 | |
| 228 // Allocate object with a slack. | |
| 216 __ movzx_b(esi, | 229 __ movzx_b(esi, |
| 217 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset)); | 230 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset)); |
| 218 __ lea(esi, | 231 __ lea(esi, |
| 219 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize)); | 232 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize)); |
| 220 // esi: offset of first field after pre-allocated fields | 233 // esi: offset of first field after pre-allocated fields |
| 221 if (FLAG_debug_code) { | 234 if (FLAG_debug_code) { |
| 222 __ cmp(esi, edi); | 235 __ cmp(esi, edi); |
| 223 __ Assert(less_equal, | 236 __ Assert(less_equal, |
| 224 kUnexpectedNumberOfPreAllocatedPropertyFields); | 237 kUnexpectedNumberOfPreAllocatedPropertyFields); |
| 225 } | 238 } |
| 226 __ InitializeFieldsWithFiller(ecx, esi, edx); | 239 __ InitializeFieldsWithFiller(ecx, esi, edx); |
| 227 __ mov(edx, factory->one_pointer_filler_map()); | 240 __ mov(edx, factory->one_pointer_filler_map()); |
| 228 __ InitializeFieldsWithFiller(ecx, edi, edx); | 241 __ InitializeFieldsWithFiller(ecx, edi, edx); |
| 229 } else if (create_memento) { | 242 __ jmp(&done_field_initialization); |
|
Michael Starzinger
2014/05/21 10:42:01
This will skip initialization of the memento even
Igor Sheludko
2014/05/22 08:05:42
Done. Now mementos are always initialized if they
| |
| 230 __ lea(esi, Operand(edi, -AllocationMemento::kSize)); | |
| 231 __ InitializeFieldsWithFiller(ecx, esi, edx); | |
| 232 | 243 |
| 233 // Fill in memento fields if necessary. | 244 __ bind(&no_inobject_slack_tracking); |
| 234 // esi: points to the allocated but uninitialized memento. | 245 |
| 235 Handle<Map> allocation_memento_map = factory->allocation_memento_map(); | 246 if (create_memento) { |
| 236 __ mov(Operand(esi, AllocationMemento::kMapOffset), | 247 __ lea(esi, Operand(edi, -AllocationMemento::kSize)); |
| 237 allocation_memento_map); | 248 __ InitializeFieldsWithFiller(ecx, esi, edx); |
| 238 // Get the cell or undefined. | 249 |
| 239 __ mov(edx, Operand(esp, kPointerSize*2)); | 250 // Fill in memento fields if necessary. |
| 240 __ mov(Operand(esi, AllocationMemento::kAllocationSiteOffset), | 251 // esi: points to the allocated but uninitialized memento. |
| 241 edx); | 252 __ mov(Operand(esi, AllocationMemento::kMapOffset), |
| 242 } else { | 253 factory->allocation_memento_map()); |
| 243 __ InitializeFieldsWithFiller(ecx, edi, edx); | 254 // Get the cell or undefined. |
| 255 __ mov(edx, Operand(esp, kPointerSize*2)); | |
| 256 __ mov(Operand(esi, AllocationMemento::kAllocationSiteOffset), | |
| 257 edx); | |
| 258 } else { | |
| 259 __ InitializeFieldsWithFiller(ecx, edi, edx); | |
| 260 } | |
| 261 __ bind(&done_field_initialization); | |
| 244 } | 262 } |
| 245 | 263 |
| 246 // Add the object tag to make the JSObject real, so that we can continue | 264 // 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 | 265 // and jump into the continuation code at any time from now on. Any |
| 248 // failures need to undo the allocation, so that the heap is in a | 266 // failures need to undo the allocation, so that the heap is in a |
| 249 // consistent state and verifiable. | 267 // consistent state and verifiable. |
| 250 // eax: initial map | 268 // eax: initial map |
| 251 // ebx: JSObject | 269 // ebx: JSObject |
| 252 // edi: start of next object | 270 // edi: start of next object |
| 253 __ or_(ebx, Immediate(kHeapObjectTag)); | 271 __ or_(ebx, Immediate(kHeapObjectTag)); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 406 Handle<Code> code = | 424 Handle<Code> code = |
| 407 masm->isolate()->builtins()->HandleApiCallConstruct(); | 425 masm->isolate()->builtins()->HandleApiCallConstruct(); |
| 408 __ call(code, RelocInfo::CODE_TARGET); | 426 __ call(code, RelocInfo::CODE_TARGET); |
| 409 } else { | 427 } else { |
| 410 ParameterCount actual(eax); | 428 ParameterCount actual(eax); |
| 411 __ InvokeFunction(edi, actual, CALL_FUNCTION, | 429 __ InvokeFunction(edi, actual, CALL_FUNCTION, |
| 412 NullCallWrapper()); | 430 NullCallWrapper()); |
| 413 } | 431 } |
| 414 | 432 |
| 415 // Store offset of return address for deoptimizer. | 433 // Store offset of return address for deoptimizer. |
| 416 if (!is_api_function && !count_constructions) { | 434 if (!is_api_function) { |
| 417 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); | 435 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); |
| 418 } | 436 } |
| 419 | 437 |
| 420 // Restore context from the frame. | 438 // Restore context from the frame. |
| 421 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 439 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 422 | 440 |
| 423 // If the result is an object (in the ECMA sense), we should get rid | 441 // 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 | 442 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 |
| 425 // on page 74. | 443 // on page 74. |
| 426 Label use_receiver, exit; | 444 Label use_receiver, exit; |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 448 // Remove caller arguments from the stack and return. | 466 // Remove caller arguments from the stack and return. |
| 449 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 467 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
| 450 __ pop(ecx); | 468 __ pop(ecx); |
| 451 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver | 469 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver |
| 452 __ push(ecx); | 470 __ push(ecx); |
| 453 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); | 471 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); |
| 454 __ ret(0); | 472 __ ret(0); |
| 455 } | 473 } |
| 456 | 474 |
| 457 | 475 |
| 458 void Builtins::Generate_JSConstructStubCountdown(MacroAssembler* masm) { | |
| 459 Generate_JSConstructStubHelper(masm, false, true, false); | |
| 460 } | |
| 461 | |
| 462 | |
| 463 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { | 476 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { |
| 464 Generate_JSConstructStubHelper(masm, false, false, FLAG_pretenuring_call_new); | 477 Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new); |
| 465 } | 478 } |
| 466 | 479 |
| 467 | 480 |
| 468 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { | 481 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { |
| 469 Generate_JSConstructStubHelper(masm, true, false, false); | 482 Generate_JSConstructStubHelper(masm, true, false); |
| 470 } | 483 } |
| 471 | 484 |
| 472 | 485 |
| 473 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, | 486 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
| 474 bool is_construct) { | 487 bool is_construct) { |
| 475 ProfileEntryHookStub::MaybeCallEntryHook(masm); | 488 ProfileEntryHookStub::MaybeCallEntryHook(masm); |
| 476 | 489 |
| 477 // Clear the context before we push it when entering the internal frame. | 490 // Clear the context before we push it when entering the internal frame. |
| 478 __ Move(esi, Immediate(0)); | 491 __ Move(esi, Immediate(0)); |
| 479 | 492 |
| (...skipping 954 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1434 | 1447 |
| 1435 __ bind(&ok); | 1448 __ bind(&ok); |
| 1436 __ ret(0); | 1449 __ ret(0); |
| 1437 } | 1450 } |
| 1438 | 1451 |
| 1439 #undef __ | 1452 #undef __ |
| 1440 } | 1453 } |
| 1441 } // namespace v8::internal | 1454 } // namespace v8::internal |
| 1442 | 1455 |
| 1443 #endif // V8_TARGET_ARCH_IA32 | 1456 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |