| 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 #if V8_TARGET_ARCH_X87 |     5 #if V8_TARGET_ARCH_X87 | 
|     6  |     6  | 
|     7 #include "src/code-factory.h" |     7 #include "src/code-factory.h" | 
|     8 #include "src/codegen.h" |     8 #include "src/codegen.h" | 
|     9 #include "src/deoptimizer.h" |     9 #include "src/deoptimizer.h" | 
|    10 #include "src/full-codegen/full-codegen.h" |    10 #include "src/full-codegen/full-codegen.h" | 
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   115  |   115  | 
|   116   CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode); |   116   CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode); | 
|   117   GenerateTailCallToReturnedCode(masm); |   117   GenerateTailCallToReturnedCode(masm); | 
|   118  |   118  | 
|   119   __ bind(&ok); |   119   __ bind(&ok); | 
|   120   GenerateTailCallToSharedCode(masm); |   120   GenerateTailCallToSharedCode(masm); | 
|   121 } |   121 } | 
|   122  |   122  | 
|   123  |   123  | 
|   124 static void Generate_JSConstructStubHelper(MacroAssembler* masm, |   124 static void Generate_JSConstructStubHelper(MacroAssembler* masm, | 
|   125                                            bool is_api_function) { |   125                                            bool is_api_function, | 
 |   126                                            bool create_implicit_receiver) { | 
|   126   // ----------- S t a t e ------------- |   127   // ----------- S t a t e ------------- | 
|   127   //  -- eax: number of arguments |   128   //  -- eax: number of arguments | 
|   128   //  -- edi: constructor function |   129   //  -- edi: constructor function | 
|   129   //  -- ebx: allocation site or undefined |   130   //  -- ebx: allocation site or undefined | 
|   130   //  -- edx: new target |   131   //  -- edx: new target | 
|   131   // ----------------------------------- |   132   // ----------------------------------- | 
|   132  |   133  | 
|   133   // Enter a construct frame. |   134   // Enter a construct frame. | 
|   134   { |   135   { | 
|   135     FrameScope scope(masm, StackFrame::CONSTRUCT); |   136     FrameScope scope(masm, StackFrame::CONSTRUCT); | 
|   136  |   137  | 
|   137     // Preserve the incoming parameters on the stack. |   138     // Preserve the incoming parameters on the stack. | 
|   138     __ AssertUndefinedOrAllocationSite(ebx); |   139     __ AssertUndefinedOrAllocationSite(ebx); | 
|   139     __ push(ebx); |   140     __ push(ebx); | 
|   140     __ SmiTag(eax); |   141     __ SmiTag(eax); | 
|   141     __ push(eax); |   142     __ push(eax); | 
|   142     __ push(edi); |  | 
|   143     __ push(edx); |  | 
|   144  |   143  | 
|   145     // Try to allocate the object without transitioning into C code. If any of |   144     if (create_implicit_receiver) { | 
|   146     // the preconditions is not met, the code bails out to the runtime call. |   145       __ push(edi); | 
|   147     Label rt_call, allocated; |   146       __ push(edx); | 
|   148     if (FLAG_inline_new) { |  | 
|   149       // Verify that the new target is a JSFunction. |  | 
|   150       __ CmpObjectType(edx, JS_FUNCTION_TYPE, ebx); |  | 
|   151       __ j(not_equal, &rt_call); |  | 
|   152  |   147  | 
|   153       // Load the initial map and verify that it is in fact a map. |   148       // Try to allocate the object without transitioning into C code. If any of | 
|   154       // edx: new target |   149       // the preconditions is not met, the code bails out to the runtime call. | 
|   155       __ mov(eax, FieldOperand(edx, JSFunction::kPrototypeOrInitialMapOffset)); |   150       Label rt_call, allocated; | 
|   156       // Will both indicate a NULL and a Smi |   151       if (FLAG_inline_new) { | 
|   157       __ JumpIfSmi(eax, &rt_call); |   152         // Verify that the new target is a JSFunction. | 
|   158       // edi: constructor |   153         __ CmpObjectType(edx, JS_FUNCTION_TYPE, ebx); | 
|   159       // eax: initial map (if proven valid below) |   154         __ j(not_equal, &rt_call); | 
|   160       __ CmpObjectType(eax, MAP_TYPE, ebx); |  | 
|   161       __ j(not_equal, &rt_call); |  | 
|   162  |   155  | 
|   163       // Fall back to runtime if the expected base constructor and base |   156         // Load the initial map and verify that it is in fact a map. | 
|   164       // constructor differ. |   157         // edx: new target | 
|   165       __ cmp(edi, FieldOperand(eax, Map::kConstructorOrBackPointerOffset)); |   158         __ mov(eax, | 
|   166       __ j(not_equal, &rt_call); |   159                FieldOperand(edx, JSFunction::kPrototypeOrInitialMapOffset)); | 
 |   160         // Will both indicate a NULL and a Smi | 
 |   161         __ JumpIfSmi(eax, &rt_call); | 
 |   162         // edi: constructor | 
 |   163         // eax: initial map (if proven valid below) | 
 |   164         __ CmpObjectType(eax, MAP_TYPE, ebx); | 
 |   165         __ j(not_equal, &rt_call); | 
|   167  |   166  | 
|   168       // Check that the constructor is not constructing a JSFunction (see |   167         // Fall back to runtime if the expected base constructor and base | 
|   169       // comments in Runtime_NewObject in runtime.cc). In which case the |   168         // constructor differ. | 
|   170       // initial map's instance type would be JS_FUNCTION_TYPE. |   169         __ cmp(edi, FieldOperand(eax, Map::kConstructorOrBackPointerOffset)); | 
|   171       // edi: constructor |   170         __ j(not_equal, &rt_call); | 
|   172       // eax: initial map |  | 
|   173       __ CmpInstanceType(eax, JS_FUNCTION_TYPE); |  | 
|   174       __ j(equal, &rt_call); |  | 
|   175  |   171  | 
|   176       if (!is_api_function) { |   172         // Check that the constructor is not constructing a JSFunction (see | 
|   177         Label allocate; |   173         // comments in Runtime_NewObject in runtime.cc). In which case the | 
|   178         // The code below relies on these assumptions. |   174         // initial map's instance type would be JS_FUNCTION_TYPE. | 
|   179         STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32); |   175         // edi: constructor | 
|   180         // Check if slack tracking is enabled. |   176         // eax: initial map | 
|   181         __ mov(esi, FieldOperand(eax, Map::kBitField3Offset)); |   177         __ CmpInstanceType(eax, JS_FUNCTION_TYPE); | 
|   182         __ shr(esi, Map::Counter::kShift); |   178         __ j(equal, &rt_call); | 
|   183         __ cmp(esi, Map::kSlackTrackingCounterEnd); |  | 
|   184         __ j(less, &allocate); |  | 
|   185         // Decrease generous allocation count. |  | 
|   186         __ sub(FieldOperand(eax, Map::kBitField3Offset), |  | 
|   187                Immediate(1 << Map::Counter::kShift)); |  | 
|   188  |   179  | 
|   189         __ cmp(esi, Map::kSlackTrackingCounterEnd); |   180         if (!is_api_function) { | 
|   190         __ j(not_equal, &allocate); |   181           Label allocate; | 
 |   182           // The code below relies on these assumptions. | 
 |   183           STATIC_ASSERT(Map::Counter::kShift + Map::Counter::kSize == 32); | 
 |   184           // Check if slack tracking is enabled. | 
 |   185           __ mov(esi, FieldOperand(eax, Map::kBitField3Offset)); | 
 |   186           __ shr(esi, Map::Counter::kShift); | 
 |   187           __ cmp(esi, Map::kSlackTrackingCounterEnd); | 
 |   188           __ j(less, &allocate); | 
 |   189           // Decrease generous allocation count. | 
 |   190           __ sub(FieldOperand(eax, Map::kBitField3Offset), | 
 |   191                  Immediate(1 << Map::Counter::kShift)); | 
|   191  |   192  | 
|   192         __ push(eax); |   193           __ cmp(esi, Map::kSlackTrackingCounterEnd); | 
|   193         __ push(edx); |   194           __ j(not_equal, &allocate); | 
|   194         __ push(edi); |  | 
|   195  |   195  | 
|   196         __ push(eax);  // initial map |   196           __ push(eax); | 
|   197         __ CallRuntime(Runtime::kFinalizeInstanceSize, 1); |   197           __ push(edx); | 
 |   198           __ push(edi); | 
|   198  |   199  | 
|   199         __ pop(edi); |   200           __ push(eax);  // initial map | 
|   200         __ pop(edx); |   201           __ CallRuntime(Runtime::kFinalizeInstanceSize, 1); | 
|   201         __ pop(eax); |  | 
|   202         __ mov(esi, Map::kSlackTrackingCounterEnd - 1); |  | 
|   203  |   202  | 
|   204         __ bind(&allocate); |   203           __ pop(edi); | 
 |   204           __ pop(edx); | 
 |   205           __ pop(eax); | 
 |   206           __ mov(esi, Map::kSlackTrackingCounterEnd - 1); | 
 |   207  | 
 |   208           __ bind(&allocate); | 
 |   209         } | 
 |   210  | 
 |   211         // Now allocate the JSObject on the heap. | 
 |   212         // edi: constructor | 
 |   213         // eax: initial map | 
 |   214         __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset)); | 
 |   215         __ shl(edi, kPointerSizeLog2); | 
 |   216  | 
 |   217         __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); | 
 |   218  | 
 |   219         Factory* factory = masm->isolate()->factory(); | 
 |   220  | 
 |   221         // Allocated the JSObject, now initialize the fields. | 
 |   222         // eax: initial map | 
 |   223         // ebx: JSObject | 
 |   224         // edi: start of next object | 
 |   225         __ mov(Operand(ebx, JSObject::kMapOffset), eax); | 
 |   226         __ mov(ecx, factory->empty_fixed_array()); | 
 |   227         __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx); | 
 |   228         __ mov(Operand(ebx, JSObject::kElementsOffset), ecx); | 
 |   229         // Set extra fields in the newly allocated object. | 
 |   230         // eax: initial map | 
 |   231         // ebx: JSObject | 
 |   232         // edi: start of next object | 
 |   233         // esi: slack tracking counter (non-API function case) | 
 |   234         __ mov(edx, factory->undefined_value()); | 
 |   235         __ lea(ecx, Operand(ebx, JSObject::kHeaderSize)); | 
 |   236         if (!is_api_function) { | 
 |   237           Label no_inobject_slack_tracking; | 
 |   238  | 
 |   239           // Check if slack tracking is enabled. | 
 |   240           __ cmp(esi, Map::kSlackTrackingCounterEnd); | 
 |   241           __ j(less, &no_inobject_slack_tracking); | 
 |   242  | 
 |   243           // Allocate object with a slack. | 
 |   244           __ movzx_b( | 
 |   245               esi, | 
 |   246               FieldOperand( | 
 |   247                   eax, | 
 |   248                   Map::kInObjectPropertiesOrConstructorFunctionIndexOffset)); | 
 |   249           __ movzx_b(eax, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset)); | 
 |   250           __ sub(esi, eax); | 
 |   251           __ lea(esi, | 
 |   252                  Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize)); | 
 |   253           // esi: offset of first field after pre-allocated fields | 
 |   254           if (FLAG_debug_code) { | 
 |   255             __ cmp(esi, edi); | 
 |   256             __ Assert(less_equal, | 
 |   257                       kUnexpectedNumberOfPreAllocatedPropertyFields); | 
 |   258           } | 
 |   259           __ InitializeFieldsWithFiller(ecx, esi, edx); | 
 |   260           __ mov(edx, factory->one_pointer_filler_map()); | 
 |   261           // Fill the remaining fields with one pointer filler map. | 
 |   262  | 
 |   263           __ bind(&no_inobject_slack_tracking); | 
 |   264         } | 
 |   265  | 
 |   266         __ InitializeFieldsWithFiller(ecx, edi, edx); | 
 |   267  | 
 |   268         // Add the object tag to make the JSObject real, so that we can continue | 
 |   269         // and jump into the continuation code at any time from now on. | 
 |   270         // ebx: JSObject (untagged) | 
 |   271         __ or_(ebx, Immediate(kHeapObjectTag)); | 
 |   272  | 
 |   273         // Continue with JSObject being successfully allocated | 
 |   274         // ebx: JSObject (tagged) | 
 |   275         __ jmp(&allocated); | 
|   205       } |   276       } | 
|   206  |   277  | 
|   207       // Now allocate the JSObject on the heap. |   278       // Allocate the new receiver object using the runtime call. | 
|   208       // edi: constructor |   279       // edx: new target | 
|   209       // eax: initial map |   280       __ bind(&rt_call); | 
|   210       __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset)); |   281       int offset = kPointerSize; | 
|   211       __ shl(edi, kPointerSizeLog2); |  | 
|   212  |   282  | 
|   213       __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); |   283       // Must restore esi (context) and edi (constructor) before calling | 
 |   284       // runtime. | 
 |   285       __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 
 |   286       __ mov(edi, Operand(esp, offset)); | 
 |   287       __ push(edi);  // constructor function | 
 |   288       __ push(edx);  // new target | 
 |   289       __ CallRuntime(Runtime::kNewObject, 2); | 
 |   290       __ mov(ebx, eax);  // store result in ebx | 
|   214  |   291  | 
|   215       Factory* factory = masm->isolate()->factory(); |   292       // New object allocated. | 
 |   293       // ebx: newly allocated object | 
 |   294       __ bind(&allocated); | 
|   216  |   295  | 
|   217       // Allocated the JSObject, now initialize the fields. |   296       // Restore the parameters. | 
|   218       // eax: initial map |   297       __ pop(edx);  // new.target | 
|   219       // ebx: JSObject |   298       __ pop(edi);  // Constructor function. | 
|   220       // edi: start of next object |  | 
|   221       __ mov(Operand(ebx, JSObject::kMapOffset), eax); |  | 
|   222       __ mov(ecx, factory->empty_fixed_array()); |  | 
|   223       __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx); |  | 
|   224       __ mov(Operand(ebx, JSObject::kElementsOffset), ecx); |  | 
|   225       // Set extra fields in the newly allocated object. |  | 
|   226       // eax: initial map |  | 
|   227       // ebx: JSObject |  | 
|   228       // edi: start of next object |  | 
|   229       // esi: slack tracking counter (non-API function case) |  | 
|   230       __ mov(edx, factory->undefined_value()); |  | 
|   231       __ lea(ecx, Operand(ebx, JSObject::kHeaderSize)); |  | 
|   232       if (!is_api_function) { |  | 
|   233         Label no_inobject_slack_tracking; |  | 
|   234  |   299  | 
|   235         // Check if slack tracking is enabled. |   300       // Retrieve smi-tagged arguments count from the stack. | 
|   236         __ cmp(esi, Map::kSlackTrackingCounterEnd); |   301       __ mov(eax, Operand(esp, 0)); | 
|   237         __ j(less, &no_inobject_slack_tracking); |  | 
|   238  |  | 
|   239         // Allocate object with a slack. |  | 
|   240         __ movzx_b( |  | 
|   241             esi, |  | 
|   242             FieldOperand( |  | 
|   243                 eax, Map::kInObjectPropertiesOrConstructorFunctionIndexOffset)); |  | 
|   244         __ movzx_b(eax, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset)); |  | 
|   245         __ sub(esi, eax); |  | 
|   246         __ lea(esi, |  | 
|   247                Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize)); |  | 
|   248         // esi: offset of first field after pre-allocated fields |  | 
|   249         if (FLAG_debug_code) { |  | 
|   250           __ cmp(esi, edi); |  | 
|   251           __ Assert(less_equal, |  | 
|   252                     kUnexpectedNumberOfPreAllocatedPropertyFields); |  | 
|   253         } |  | 
|   254         __ InitializeFieldsWithFiller(ecx, esi, edx); |  | 
|   255         __ mov(edx, factory->one_pointer_filler_map()); |  | 
|   256         // Fill the remaining fields with one pointer filler map. |  | 
|   257  |  | 
|   258         __ bind(&no_inobject_slack_tracking); |  | 
|   259       } |  | 
|   260  |  | 
|   261       __ InitializeFieldsWithFiller(ecx, edi, edx); |  | 
|   262  |  | 
|   263       // Add the object tag to make the JSObject real, so that we can continue |  | 
|   264       // and jump into the continuation code at any time from now on. |  | 
|   265       // ebx: JSObject (untagged) |  | 
|   266       __ or_(ebx, Immediate(kHeapObjectTag)); |  | 
|   267  |  | 
|   268       // Continue with JSObject being successfully allocated |  | 
|   269       // ebx: JSObject (tagged) |  | 
|   270       __ jmp(&allocated); |  | 
|   271     } |   302     } | 
|   272  |   303  | 
|   273     // Allocate the new receiver object using the runtime call. |  | 
|   274     // edx: new target |  | 
|   275     __ bind(&rt_call); |  | 
|   276     int offset = kPointerSize; |  | 
|   277  |  | 
|   278     // Must restore esi (context) and edi (constructor) before calling |  | 
|   279     // runtime. |  | 
|   280     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |  | 
|   281     __ mov(edi, Operand(esp, offset)); |  | 
|   282     __ push(edi);  // constructor function |  | 
|   283     __ push(edx);  // new target |  | 
|   284     __ CallRuntime(Runtime::kNewObject, 2); |  | 
|   285     __ mov(ebx, eax);  // store result in ebx |  | 
|   286  |  | 
|   287     // New object allocated. |  | 
|   288     // ebx: newly allocated object |  | 
|   289     __ bind(&allocated); |  | 
|   290  |  | 
|   291     // Restore the parameters. |  | 
|   292     __ pop(edx);  // new.target |  | 
|   293     __ pop(edi);  // Constructor function. |  | 
|   294  |  | 
|   295     // Retrieve smi-tagged arguments count from the stack. |  | 
|   296     __ mov(eax, Operand(esp, 0)); |  | 
|   297     __ SmiUntag(eax); |   304     __ SmiUntag(eax); | 
|   298  |   305  | 
|   299     // Push new.target onto the construct frame. This is stored just below the |   306     // Push new.target onto the construct frame. This is stored just below the | 
|   300     // receiver on the stack. |   307     // receiver on the stack. | 
|   301     __ push(edx); |   308     __ push(edx); | 
|   302  |   309  | 
|   303     // Push the allocated receiver to the stack. We need two copies |   310     if (create_implicit_receiver) { | 
|   304     // because we may have to return the original one and the calling |   311       // Push the allocated receiver to the stack. We need two copies | 
|   305     // conventions dictate that the called function pops the receiver. |   312       // because we may have to return the original one and the calling | 
|   306     __ push(ebx); |   313       // conventions dictate that the called function pops the receiver. | 
|   307     __ push(ebx); |   314       __ push(ebx); | 
 |   315       __ push(ebx); | 
 |   316     } else { | 
 |   317       __ PushRoot(Heap::kTheHoleValueRootIndex); | 
 |   318     } | 
|   308  |   319  | 
|   309     // Set up pointer to last argument. |   320     // Set up pointer to last argument. | 
|   310     __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); |   321     __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); | 
|   311  |   322  | 
|   312     // Copy arguments and receiver to the expression stack. |   323     // Copy arguments and receiver to the expression stack. | 
|   313     Label loop, entry; |   324     Label loop, entry; | 
|   314     __ mov(ecx, eax); |   325     __ mov(ecx, eax); | 
|   315     __ jmp(&entry); |   326     __ jmp(&entry); | 
|   316     __ bind(&loop); |   327     __ bind(&loop); | 
|   317     __ push(Operand(ebx, ecx, times_4, 0)); |   328     __ push(Operand(ebx, ecx, times_4, 0)); | 
|   318     __ bind(&entry); |   329     __ bind(&entry); | 
|   319     __ dec(ecx); |   330     __ dec(ecx); | 
|   320     __ j(greater_equal, &loop); |   331     __ j(greater_equal, &loop); | 
|   321  |   332  | 
|   322     // Call the function. |   333     // Call the function. | 
|   323     if (is_api_function) { |   334     if (is_api_function) { | 
|   324       __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |   335       __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 
|   325       Handle<Code> code = |   336       Handle<Code> code = | 
|   326           masm->isolate()->builtins()->HandleApiCallConstruct(); |   337           masm->isolate()->builtins()->HandleApiCallConstruct(); | 
|   327       __ call(code, RelocInfo::CODE_TARGET); |   338       __ call(code, RelocInfo::CODE_TARGET); | 
|   328     } else { |   339     } else { | 
|   329       ParameterCount actual(eax); |   340       ParameterCount actual(eax); | 
|   330       __ InvokeFunction(edi, actual, CALL_FUNCTION, |   341       __ InvokeFunction(edi, actual, CALL_FUNCTION, | 
|   331                         NullCallWrapper()); |   342                         NullCallWrapper()); | 
|   332     } |   343     } | 
|   333  |   344  | 
|   334     // Store offset of return address for deoptimizer. |   345     // Store offset of return address for deoptimizer. | 
|   335     if (!is_api_function) { |   346     if (create_implicit_receiver && !is_api_function) { | 
|   336       masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); |   347       masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); | 
|   337     } |   348     } | 
|   338  |   349  | 
|   339     // Restore context from the frame. |   350     // Restore context from the frame. | 
|   340     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |   351     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 
|   341  |   352  | 
|   342     // If the result is an object (in the ECMA sense), we should get rid |   353     if (create_implicit_receiver) { | 
|   343     // of the receiver and use the result; see ECMA-262 section 13.2.2-7 |   354       // If the result is an object (in the ECMA sense), we should get rid | 
|   344     // on page 74. |   355       // of the receiver and use the result; see ECMA-262 section 13.2.2-7 | 
|   345     Label use_receiver, exit; |   356       // on page 74. | 
 |   357       Label use_receiver, exit; | 
|   346  |   358  | 
|   347     // If the result is a smi, it is *not* an object in the ECMA sense. |   359       // If the result is a smi, it is *not* an object in the ECMA sense. | 
|   348     __ JumpIfSmi(eax, &use_receiver); |   360       __ JumpIfSmi(eax, &use_receiver); | 
|   349  |   361  | 
|   350     // If the type of the result (stored in its map) is less than |   362       // If the type of the result (stored in its map) is less than | 
|   351     // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. |   363       // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. | 
|   352     __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); |   364       __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); | 
|   353     __ j(above_equal, &exit); |   365       __ j(above_equal, &exit); | 
|   354  |   366  | 
|   355     // Throw away the result of the constructor invocation and use the |   367       // Throw away the result of the constructor invocation and use the | 
|   356     // on-stack receiver as the result. |   368       // on-stack receiver as the result. | 
|   357     __ bind(&use_receiver); |   369       __ bind(&use_receiver); | 
|   358     __ mov(eax, Operand(esp, 0)); |   370       __ mov(eax, Operand(esp, 0)); | 
|   359  |   371  | 
|   360     // Restore the arguments count and leave the construct frame. The arguments |   372       // Restore the arguments count and leave the construct frame. The | 
|   361     // count is stored below the reciever and the new.target. |   373       // arguments | 
|   362     __ bind(&exit); |   374       // count is stored below the reciever and the new.target. | 
|   363     __ mov(ebx, Operand(esp, 2 * kPointerSize)); |   375       __ bind(&exit); | 
 |   376       __ mov(ebx, Operand(esp, 2 * kPointerSize)); | 
 |   377     } else { | 
 |   378       __ mov(ebx, Operand(esp, kPointerSize)); | 
 |   379     } | 
|   364  |   380  | 
|   365     // Leave construct frame. |   381     // Leave construct frame. | 
|   366   } |   382   } | 
|   367  |   383  | 
|   368   // Remove caller arguments from the stack and return. |   384   // Remove caller arguments from the stack and return. | 
|   369   STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |   385   STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 
|   370   __ pop(ecx); |   386   __ pop(ecx); | 
|   371   __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~ receiver |   387   __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize));  // 1 ~ receiver | 
|   372   __ push(ecx); |   388   __ push(ecx); | 
|   373   __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); |   389   if (create_implicit_receiver) { | 
 |   390     __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); | 
 |   391   } | 
|   374   __ ret(0); |   392   __ ret(0); | 
|   375 } |   393 } | 
|   376  |   394  | 
|   377  |   395  | 
|   378 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { |   396 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { | 
|   379   Generate_JSConstructStubHelper(masm, false); |   397   Generate_JSConstructStubHelper(masm, false, true); | 
|   380 } |   398 } | 
|   381  |   399  | 
|   382  |   400  | 
|   383 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { |   401 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { | 
|   384   Generate_JSConstructStubHelper(masm, true); |   402   Generate_JSConstructStubHelper(masm, true, true); | 
|   385 } |   403 } | 
|   386  |   404  | 
|   387  |   405  | 
|   388 void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) { |   406 void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) { | 
|   389   // ----------- S t a t e ------------- |   407   Generate_JSConstructStubHelper(masm, false, false); | 
|   390   //  -- eax: number of arguments |  | 
|   391   //  -- edi: constructor function |  | 
|   392   //  -- ebx: allocation site or undefined |  | 
|   393   //  -- edx: new target |  | 
|   394   // ----------------------------------- |  | 
|   395  |  | 
|   396   { |  | 
|   397     FrameScope frame_scope(masm, StackFrame::CONSTRUCT); |  | 
|   398  |  | 
|   399     // Preserve allocation site. |  | 
|   400     __ AssertUndefinedOrAllocationSite(ebx); |  | 
|   401     __ push(ebx); |  | 
|   402  |  | 
|   403     // Preserve actual arguments count. |  | 
|   404     __ SmiTag(eax); |  | 
|   405     __ push(eax); |  | 
|   406     __ SmiUntag(eax); |  | 
|   407  |  | 
|   408     // Push new.target. |  | 
|   409     __ push(edx); |  | 
|   410  |  | 
|   411     // receiver is the hole. |  | 
|   412     __ push(Immediate(masm->isolate()->factory()->the_hole_value())); |  | 
|   413  |  | 
|   414     // Set up pointer to last argument. |  | 
|   415     __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); |  | 
|   416  |  | 
|   417     // Copy arguments and receiver to the expression stack. |  | 
|   418     Label loop, entry; |  | 
|   419     __ mov(ecx, eax); |  | 
|   420     __ jmp(&entry); |  | 
|   421     __ bind(&loop); |  | 
|   422     __ push(Operand(ebx, ecx, times_4, 0)); |  | 
|   423     __ bind(&entry); |  | 
|   424     __ dec(ecx); |  | 
|   425     __ j(greater_equal, &loop); |  | 
|   426  |  | 
|   427     // Invoke function. |  | 
|   428     ParameterCount actual(eax); |  | 
|   429     __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper()); |  | 
|   430  |  | 
|   431     // Restore context from the frame. |  | 
|   432     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |  | 
|   433  |  | 
|   434     // Get arguments count, skipping over new.target. |  | 
|   435     __ mov(ebx, Operand(esp, kPointerSize)); |  | 
|   436   } |  | 
|   437  |  | 
|   438   __ pop(ecx);  // Return address. |  | 
|   439   __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); |  | 
|   440   __ push(ecx); |  | 
|   441   __ ret(0); |  | 
|   442 } |   408 } | 
|   443  |   409  | 
|   444  |   410  | 
|   445 enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt }; |   411 enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt }; | 
|   446  |   412  | 
|   447  |   413  | 
|   448 // Clobbers ecx, edx, edi; preserves all other registers. |   414 // Clobbers ecx, edx, edi; preserves all other registers. | 
|   449 static void Generate_CheckStackOverflow(MacroAssembler* masm, |   415 static void Generate_CheckStackOverflow(MacroAssembler* masm, | 
|   450                                         IsTagged eax_is_tagged) { |   416                                         IsTagged eax_is_tagged) { | 
|   451   // eax   : the number of items to be pushed to the stack |   417   // eax   : the number of items to be pushed to the stack | 
| (...skipping 1438 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1890  |  1856  | 
|  1891   __ bind(&ok); |  1857   __ bind(&ok); | 
|  1892   __ ret(0); |  1858   __ ret(0); | 
|  1893 } |  1859 } | 
|  1894  |  1860  | 
|  1895 #undef __ |  1861 #undef __ | 
|  1896 }  // namespace internal |  1862 }  // namespace internal | 
|  1897 }  // namespace v8 |  1863 }  // namespace v8 | 
|  1898  |  1864  | 
|  1899 #endif  // V8_TARGET_ARCH_X87 |  1865 #endif  // V8_TARGET_ARCH_X87 | 
| OLD | NEW |