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 3 // found in the LICENSE file. 4 5 #include "src/v8.h" 6 7 #if V8_TARGET_ARCH_X87 8 9 #include "src/code-factory.h" 10 #include "src/codegen.h" 11 #include "src/deoptimizer.h" 12 #include "src/full-codegen.h" 13 14 namespace v8 { 15 namespace internal { 16 17 18 #define __ ACCESS_MASM(masm) 19 20 Generate_Adaptor(MacroAssembler * masm,CFunctionId id,BuiltinExtraArguments extra_args)21 void Builtins::Generate_Adaptor(MacroAssembler* masm, 22 CFunctionId id, 23 BuiltinExtraArguments extra_args) { 24 // ----------- S t a t e ------------- 25 // -- eax : number of arguments excluding receiver 26 // -- edi : called function (only guaranteed when 27 // extra_args requires it) 28 // -- esi : context 29 // -- esp[0] : return address 30 // -- esp[4] : last argument 31 // -- ... 32 // -- esp[4 * argc] : first argument (argc == eax) 33 // -- esp[4 * (argc +1)] : receiver 34 // ----------------------------------- 35 36 // Insert extra arguments. 37 int num_extra_args = 0; 38 if (extra_args == NEEDS_CALLED_FUNCTION) { 39 num_extra_args = 1; 40 Register scratch = ebx; 41 __ pop(scratch); // Save return address. 42 __ push(edi); 43 __ push(scratch); // Restore return address. 44 } else { 45 DCHECK(extra_args == NO_EXTRA_ARGUMENTS); 46 } 47 48 // JumpToExternalReference expects eax to contain the number of arguments 49 // including the receiver and the extra arguments. 50 __ add(eax, Immediate(num_extra_args + 1)); 51 __ JumpToExternalReference(ExternalReference(id, masm->isolate())); 52 } 53 54 CallRuntimePassFunction(MacroAssembler * masm,Runtime::FunctionId function_id)55 static void CallRuntimePassFunction( 56 MacroAssembler* masm, Runtime::FunctionId function_id) { 57 FrameScope scope(masm, StackFrame::INTERNAL); 58 // Push a copy of the function. 59 __ push(edi); 60 // Function is also the parameter to the runtime call. 61 __ push(edi); 62 63 __ CallRuntime(function_id, 1); 64 // Restore receiver. 65 __ pop(edi); 66 } 67 68 GenerateTailCallToSharedCode(MacroAssembler * masm)69 static void GenerateTailCallToSharedCode(MacroAssembler* masm) { 70 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 71 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kCodeOffset)); 72 __ lea(eax, FieldOperand(eax, Code::kHeaderSize)); 73 __ jmp(eax); 74 } 75 76 GenerateTailCallToReturnedCode(MacroAssembler * masm)77 static void GenerateTailCallToReturnedCode(MacroAssembler* masm) { 78 __ lea(eax, FieldOperand(eax, Code::kHeaderSize)); 79 __ jmp(eax); 80 } 81 82 Generate_InOptimizationQueue(MacroAssembler * masm)83 void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) { 84 // Checking whether the queued function is ready for install is optional, 85 // since we come across interrupts and stack checks elsewhere. However, 86 // not checking may delay installing ready functions, and always checking 87 // would be quite expensive. A good compromise is to first check against 88 // stack limit as a cue for an interrupt signal. 89 Label ok; 90 ExternalReference stack_limit = 91 ExternalReference::address_of_stack_limit(masm->isolate()); 92 __ cmp(esp, Operand::StaticVariable(stack_limit)); 93 __ j(above_equal, &ok, Label::kNear); 94 95 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode); 96 GenerateTailCallToReturnedCode(masm); 97 98 __ bind(&ok); 99 GenerateTailCallToSharedCode(masm); 100 } 101 102 Generate_JSConstructStubHelper(MacroAssembler * masm,bool is_api_function,bool create_memento)103 static void Generate_JSConstructStubHelper(MacroAssembler* masm, 104 bool is_api_function, 105 bool create_memento) { 106 // ----------- S t a t e ------------- 107 // -- eax: number of arguments 108 // -- edi: constructor function 109 // -- ebx: allocation site or undefined 110 // ----------------------------------- 111 112 // Should never create mementos for api functions. 113 DCHECK(!is_api_function || !create_memento); 114 115 // Enter a construct frame. 116 { 117 FrameScope scope(masm, StackFrame::CONSTRUCT); 118 119 if (create_memento) { 120 __ AssertUndefinedOrAllocationSite(ebx); 121 __ push(ebx); 122 } 123 124 // Store a smi-tagged arguments count on the stack. 125 __ SmiTag(eax); 126 __ push(eax); 127 128 // Push the function to invoke on the stack. 129 __ push(edi); 130 131 // Try to allocate the object without transitioning into C code. If any of 132 // the preconditions is not met, the code bails out to the runtime call. 133 Label rt_call, allocated; 134 if (FLAG_inline_new) { 135 Label undo_allocation; 136 ExternalReference debug_step_in_fp = 137 ExternalReference::debug_step_in_fp_address(masm->isolate()); 138 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0)); 139 __ j(not_equal, &rt_call); 140 141 // Verified that the constructor is a JSFunction. 142 // Load the initial map and verify that it is in fact a map. 143 // edi: constructor 144 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 145 // Will both indicate a NULL and a Smi 146 __ JumpIfSmi(eax, &rt_call); 147 // edi: constructor 148 // eax: initial map (if proven valid below) 149 __ CmpObjectType(eax, MAP_TYPE, ebx); 150 __ j(not_equal, &rt_call); 151 152 // Check that the constructor is not constructing a JSFunction (see 153 // comments in Runtime_NewObject in runtime.cc). In which case the 154 // initial map's instance type would be JS_FUNCTION_TYPE. 155 // edi: constructor 156 // eax: initial map 157 __ CmpInstanceType(eax, JS_FUNCTION_TYPE); 158 __ j(equal, &rt_call); 159 160 if (!is_api_function) { 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 170 // Decrease generous allocation count. 171 __ sub(FieldOperand(eax, Map::kBitField3Offset), 172 Immediate(1 << Map::ConstructionCount::kShift)); 173 174 __ cmp(esi, JSFunction::kFinishSlackTracking); 175 __ j(not_equal, &allocate); 176 177 __ push(eax); 178 __ push(edi); 179 180 __ push(edi); // constructor 181 __ CallRuntime(Runtime::kFinalizeInstanceSize, 1); 182 183 __ pop(edi); 184 __ pop(eax); 185 __ xor_(esi, esi); // JSFunction::kNoSlackTracking 186 187 __ bind(&allocate); 188 } 189 190 // Now allocate the JSObject on the heap. 191 // edi: constructor 192 // eax: initial map 193 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset)); 194 __ shl(edi, kPointerSizeLog2); 195 if (create_memento) { 196 __ add(edi, Immediate(AllocationMemento::kSize)); 197 } 198 199 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); 200 201 Factory* factory = masm->isolate()->factory(); 202 203 // Allocated the JSObject, now initialize the fields. 204 // eax: initial map 205 // ebx: JSObject 206 // edi: start of next object (including memento if create_memento) 207 __ mov(Operand(ebx, JSObject::kMapOffset), eax); 208 __ mov(ecx, factory->empty_fixed_array()); 209 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx); 210 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx); 211 // Set extra fields in the newly allocated object. 212 // eax: initial map 213 // ebx: JSObject 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()); 217 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize)); 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, 227 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset)); 228 __ lea(esi, 229 Operand(ebx, esi, times_pointer_size, JSObject::kHeaderSize)); 230 // esi: offset of first field after pre-allocated fields 231 if (FLAG_debug_code) { 232 __ cmp(esi, edi); 233 __ Assert(less_equal, 234 kUnexpectedNumberOfPreAllocatedPropertyFields); 235 } 236 __ InitializeFieldsWithFiller(ecx, esi, edx); 237 __ mov(edx, factory->one_pointer_filler_map()); 238 // Fill the remaining fields with one pointer filler map. 239 240 __ bind(&no_inobject_slack_tracking); 241 } 242 243 if (create_memento) { 244 __ lea(esi, Operand(edi, -AllocationMemento::kSize)); 245 __ InitializeFieldsWithFiller(ecx, esi, edx); 246 247 // Fill in memento fields if necessary. 248 // esi: points to the allocated but uninitialized memento. 249 __ mov(Operand(esi, AllocationMemento::kMapOffset), 250 factory->allocation_memento_map()); 251 // Get the cell or undefined. 252 __ mov(edx, Operand(esp, kPointerSize*2)); 253 __ mov(Operand(esi, AllocationMemento::kAllocationSiteOffset), 254 edx); 255 } else { 256 __ InitializeFieldsWithFiller(ecx, edi, edx); 257 } 258 259 // 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 261 // failures need to undo the allocation, so that the heap is in a 262 // consistent state and verifiable. 263 // eax: initial map 264 // ebx: JSObject 265 // edi: start of next object 266 __ or_(ebx, Immediate(kHeapObjectTag)); 267 268 // Check if a non-empty properties array is needed. 269 // Allocate and initialize a FixedArray if it is. 270 // eax: initial map 271 // ebx: JSObject 272 // edi: start of next object 273 // Calculate the total number of properties described by the map. 274 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset)); 275 __ movzx_b(ecx, 276 FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset)); 277 __ add(edx, ecx); 278 // Calculate unused properties past the end of the in-object properties. 279 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset)); 280 __ sub(edx, ecx); 281 // Done if no extra properties are to be allocated. 282 __ j(zero, &allocated); 283 __ Assert(positive, kPropertyAllocationCountFailed); 284 285 // Scale the number of elements by pointer size and add the header for 286 // FixedArrays to the start of the next object calculation from above. 287 // ebx: JSObject 288 // edi: start of next object (will be start of FixedArray) 289 // edx: number of elements in properties array 290 __ Allocate(FixedArray::kHeaderSize, 291 times_pointer_size, 292 edx, 293 REGISTER_VALUE_IS_INT32, 294 edi, 295 ecx, 296 no_reg, 297 &undo_allocation, 298 RESULT_CONTAINS_TOP); 299 300 // Initialize the FixedArray. 301 // ebx: JSObject 302 // edi: FixedArray 303 // edx: number of elements 304 // ecx: start of next object 305 __ mov(eax, factory->fixed_array_map()); 306 __ mov(Operand(edi, FixedArray::kMapOffset), eax); // setup the map 307 __ SmiTag(edx); 308 __ mov(Operand(edi, FixedArray::kLengthOffset), edx); // and length 309 310 // Initialize the fields to undefined. 311 // ebx: JSObject 312 // edi: FixedArray 313 // ecx: start of next object 314 { Label loop, entry; 315 __ mov(edx, factory->undefined_value()); 316 __ lea(eax, Operand(edi, FixedArray::kHeaderSize)); 317 __ jmp(&entry); 318 __ bind(&loop); 319 __ mov(Operand(eax, 0), edx); 320 __ add(eax, Immediate(kPointerSize)); 321 __ bind(&entry); 322 __ cmp(eax, ecx); 323 __ j(below, &loop); 324 } 325 326 // Store the initialized FixedArray into the properties field of 327 // the JSObject 328 // ebx: JSObject 329 // edi: FixedArray 330 __ or_(edi, Immediate(kHeapObjectTag)); // add the heap tag 331 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi); 332 333 334 // Continue with JSObject being successfully allocated 335 // ebx: JSObject 336 __ jmp(&allocated); 337 338 // Undo the setting of the new top so that the heap is verifiable. For 339 // example, the map's unused properties potentially do not match the 340 // allocated objects unused properties. 341 // ebx: JSObject (previous new top) 342 __ bind(&undo_allocation); 343 __ UndoAllocationInNewSpace(ebx); 344 } 345 346 // Allocate the new receiver object using the runtime call. 347 __ bind(&rt_call); 348 int offset = 0; 349 if (create_memento) { 350 // Get the cell or allocation site. 351 __ mov(edi, Operand(esp, kPointerSize * 2)); 352 __ push(edi); 353 offset = kPointerSize; 354 } 355 356 // Must restore esi (context) and edi (constructor) before calling runtime. 357 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 358 __ mov(edi, Operand(esp, offset)); 359 // edi: function (constructor) 360 __ push(edi); 361 if (create_memento) { 362 __ CallRuntime(Runtime::kNewObjectWithAllocationSite, 2); 363 } else { 364 __ CallRuntime(Runtime::kNewObject, 1); 365 } 366 __ mov(ebx, eax); // store result in ebx 367 368 // If we ended up using the runtime, and we want a memento, then the 369 // runtime call made it for us, and we shouldn't do create count 370 // increment. 371 Label count_incremented; 372 if (create_memento) { 373 __ jmp(&count_incremented); 374 } 375 376 // New object allocated. 377 // ebx: newly allocated object 378 __ bind(&allocated); 379 380 if (create_memento) { 381 __ mov(ecx, Operand(esp, kPointerSize * 2)); 382 __ cmp(ecx, masm->isolate()->factory()->undefined_value()); 383 __ j(equal, &count_incremented); 384 // ecx is an AllocationSite. We are creating a memento from it, so we 385 // need to increment the memento create count. 386 __ add(FieldOperand(ecx, AllocationSite::kPretenureCreateCountOffset), 387 Immediate(Smi::FromInt(1))); 388 __ bind(&count_incremented); 389 } 390 391 // Retrieve the function from the stack. 392 __ pop(edi); 393 394 // Retrieve smi-tagged arguments count from the stack. 395 __ mov(eax, Operand(esp, 0)); 396 __ SmiUntag(eax); 397 398 // Push the allocated receiver to the stack. We need two copies 399 // because we may have to return the original one and the calling 400 // conventions dictate that the called function pops the receiver. 401 __ push(ebx); 402 __ push(ebx); 403 404 // Set up pointer to last argument. 405 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); 406 407 // Copy arguments and receiver to the expression stack. 408 Label loop, entry; 409 __ mov(ecx, eax); 410 __ jmp(&entry); 411 __ bind(&loop); 412 __ push(Operand(ebx, ecx, times_4, 0)); 413 __ bind(&entry); 414 __ dec(ecx); 415 __ j(greater_equal, &loop); 416 417 // Call the function. 418 if (is_api_function) { 419 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 420 Handle<Code> code = 421 masm->isolate()->builtins()->HandleApiCallConstruct(); 422 __ call(code, RelocInfo::CODE_TARGET); 423 } else { 424 ParameterCount actual(eax); 425 __ InvokeFunction(edi, actual, CALL_FUNCTION, 426 NullCallWrapper()); 427 } 428 429 // Store offset of return address for deoptimizer. 430 if (!is_api_function) { 431 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); 432 } 433 434 // Restore context from the frame. 435 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 436 437 // If the result is an object (in the ECMA sense), we should get rid 438 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 439 // on page 74. 440 Label use_receiver, exit; 441 442 // If the result is a smi, it is *not* an object in the ECMA sense. 443 __ JumpIfSmi(eax, &use_receiver); 444 445 // If the type of the result (stored in its map) is less than 446 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. 447 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 448 __ j(above_equal, &exit); 449 450 // Throw away the result of the constructor invocation and use the 451 // on-stack receiver as the result. 452 __ bind(&use_receiver); 453 __ mov(eax, Operand(esp, 0)); 454 455 // Restore the arguments count and leave the construct frame. 456 __ bind(&exit); 457 __ mov(ebx, Operand(esp, kPointerSize)); // Get arguments count. 458 459 // Leave construct frame. 460 } 461 462 // Remove caller arguments from the stack and return. 463 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 464 __ pop(ecx); 465 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver 466 __ push(ecx); 467 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); 468 __ ret(0); 469 } 470 471 Generate_JSConstructStubGeneric(MacroAssembler * masm)472 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { 473 Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new); 474 } 475 476 Generate_JSConstructStubApi(MacroAssembler * masm)477 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { 478 Generate_JSConstructStubHelper(masm, true, false); 479 } 480 481 Generate_JSEntryTrampolineHelper(MacroAssembler * masm,bool is_construct)482 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, 483 bool is_construct) { 484 ProfileEntryHookStub::MaybeCallEntryHook(masm); 485 486 // Clear the context before we push it when entering the internal frame. 487 __ Move(esi, Immediate(0)); 488 489 { 490 FrameScope scope(masm, StackFrame::INTERNAL); 491 492 // Load the previous frame pointer (ebx) to access C arguments 493 __ mov(ebx, Operand(ebp, 0)); 494 495 // Get the function from the frame and setup the context. 496 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset)); 497 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset)); 498 499 // Push the function and the receiver onto the stack. 500 __ push(ecx); 501 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset)); 502 503 // Load the number of arguments and setup pointer to the arguments. 504 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset)); 505 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset)); 506 507 // Copy arguments to the stack in a loop. 508 Label loop, entry; 509 __ Move(ecx, Immediate(0)); 510 __ jmp(&entry); 511 __ bind(&loop); 512 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv 513 __ push(Operand(edx, 0)); // dereference handle 514 __ inc(ecx); 515 __ bind(&entry); 516 __ cmp(ecx, eax); 517 __ j(not_equal, &loop); 518 519 // Get the function from the stack and call it. 520 // kPointerSize for the receiver. 521 __ mov(edi, Operand(esp, eax, times_4, kPointerSize)); 522 523 // Invoke the code. 524 if (is_construct) { 525 // No type feedback cell is available 526 __ mov(ebx, masm->isolate()->factory()->undefined_value()); 527 CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS); 528 __ CallStub(&stub); 529 } else { 530 ParameterCount actual(eax); 531 __ InvokeFunction(edi, actual, CALL_FUNCTION, 532 NullCallWrapper()); 533 } 534 535 // Exit the internal frame. Notice that this also removes the empty. 536 // context and the function left on the stack by the code 537 // invocation. 538 } 539 __ ret(kPointerSize); // Remove receiver. 540 } 541 542 Generate_JSEntryTrampoline(MacroAssembler * masm)543 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { 544 Generate_JSEntryTrampolineHelper(masm, false); 545 } 546 547 Generate_JSConstructEntryTrampoline(MacroAssembler * masm)548 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { 549 Generate_JSEntryTrampolineHelper(masm, true); 550 } 551 552 Generate_CompileLazy(MacroAssembler * masm)553 void Builtins::Generate_CompileLazy(MacroAssembler* masm) { 554 CallRuntimePassFunction(masm, Runtime::kCompileLazy); 555 GenerateTailCallToReturnedCode(masm); 556 } 557 558 559 CallCompileOptimized(MacroAssembler * masm,bool concurrent)560 static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) { 561 FrameScope scope(masm, StackFrame::INTERNAL); 562 // Push a copy of the function. 563 __ push(edi); 564 // Function is also the parameter to the runtime call. 565 __ push(edi); 566 // Whether to compile in a background thread. 567 __ Push(masm->isolate()->factory()->ToBoolean(concurrent)); 568 569 __ CallRuntime(Runtime::kCompileOptimized, 2); 570 // Restore receiver. 571 __ pop(edi); 572 } 573 574 Generate_CompileOptimized(MacroAssembler * masm)575 void Builtins::Generate_CompileOptimized(MacroAssembler* masm) { 576 CallCompileOptimized(masm, false); 577 GenerateTailCallToReturnedCode(masm); 578 } 579 580 Generate_CompileOptimizedConcurrent(MacroAssembler * masm)581 void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) { 582 CallCompileOptimized(masm, true); 583 GenerateTailCallToReturnedCode(masm); 584 } 585 586 GenerateMakeCodeYoungAgainCommon(MacroAssembler * masm)587 static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) { 588 // For now, we are relying on the fact that make_code_young doesn't do any 589 // garbage collection which allows us to save/restore the registers without 590 // worrying about which of them contain pointers. We also don't build an 591 // internal frame to make the code faster, since we shouldn't have to do stack 592 // crawls in MakeCodeYoung. This seems a bit fragile. 593 594 // Re-execute the code that was patched back to the young age when 595 // the stub returns. 596 __ sub(Operand(esp, 0), Immediate(5)); 597 __ pushad(); 598 __ mov(eax, Operand(esp, 8 * kPointerSize)); 599 { 600 FrameScope scope(masm, StackFrame::MANUAL); 601 __ PrepareCallCFunction(2, ebx); 602 __ mov(Operand(esp, 1 * kPointerSize), 603 Immediate(ExternalReference::isolate_address(masm->isolate()))); 604 __ mov(Operand(esp, 0), eax); 605 __ CallCFunction( 606 ExternalReference::get_make_code_young_function(masm->isolate()), 2); 607 } 608 __ popad(); 609 __ ret(0); 610 } 611 612 #define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \ 613 void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \ 614 MacroAssembler* masm) { \ 615 GenerateMakeCodeYoungAgainCommon(masm); \ 616 } \ 617 void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \ 618 MacroAssembler* masm) { \ 619 GenerateMakeCodeYoungAgainCommon(masm); \ 620 } CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)621 CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR) 622 #undef DEFINE_CODE_AGE_BUILTIN_GENERATOR 623 624 625 void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) { 626 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact 627 // that make_code_young doesn't do any garbage collection which allows us to 628 // save/restore the registers without worrying about which of them contain 629 // pointers. 630 __ pushad(); 631 __ mov(eax, Operand(esp, 8 * kPointerSize)); 632 __ sub(eax, Immediate(Assembler::kCallInstructionLength)); 633 { // NOLINT 634 FrameScope scope(masm, StackFrame::MANUAL); 635 __ PrepareCallCFunction(2, ebx); 636 __ mov(Operand(esp, 1 * kPointerSize), 637 Immediate(ExternalReference::isolate_address(masm->isolate()))); 638 __ mov(Operand(esp, 0), eax); 639 __ CallCFunction( 640 ExternalReference::get_mark_code_as_executed_function(masm->isolate()), 641 2); 642 } 643 __ popad(); 644 645 // Perform prologue operations usually performed by the young code stub. 646 __ pop(eax); // Pop return address into scratch register. 647 __ push(ebp); // Caller's frame pointer. 648 __ mov(ebp, esp); 649 __ push(esi); // Callee's context. 650 __ push(edi); // Callee's JS Function. 651 __ push(eax); // Push return address after frame prologue. 652 653 // Jump to point after the code-age stub. 654 __ ret(0); 655 } 656 657 Generate_MarkCodeAsExecutedTwice(MacroAssembler * masm)658 void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) { 659 GenerateMakeCodeYoungAgainCommon(masm); 660 } 661 662 Generate_NotifyStubFailureHelper(MacroAssembler * masm,SaveFPRegsMode save_doubles)663 static void Generate_NotifyStubFailureHelper(MacroAssembler* masm, 664 SaveFPRegsMode save_doubles) { 665 // Enter an internal frame. 666 { 667 FrameScope scope(masm, StackFrame::INTERNAL); 668 669 // Preserve registers across notification, this is important for compiled 670 // stubs that tail call the runtime on deopts passing their parameters in 671 // registers. 672 __ pushad(); 673 __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles); 674 __ popad(); 675 // Tear down internal frame. 676 } 677 678 __ pop(MemOperand(esp, 0)); // Ignore state offset 679 __ ret(0); // Return to IC Miss stub, continuation still on stack. 680 } 681 682 Generate_NotifyStubFailure(MacroAssembler * masm)683 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) { 684 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs); 685 } 686 687 Generate_NotifyStubFailureSaveDoubles(MacroAssembler * masm)688 void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) { 689 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs); 690 } 691 692 Generate_NotifyDeoptimizedHelper(MacroAssembler * masm,Deoptimizer::BailoutType type)693 static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, 694 Deoptimizer::BailoutType type) { 695 { 696 FrameScope scope(masm, StackFrame::INTERNAL); 697 698 // Pass deoptimization type to the runtime system. 699 __ push(Immediate(Smi::FromInt(static_cast<int>(type)))); 700 __ CallRuntime(Runtime::kNotifyDeoptimized, 1); 701 702 // Tear down internal frame. 703 } 704 705 // Get the full codegen state from the stack and untag it. 706 __ mov(ecx, Operand(esp, 1 * kPointerSize)); 707 __ SmiUntag(ecx); 708 709 // Switch on the state. 710 Label not_no_registers, not_tos_eax; 711 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS); 712 __ j(not_equal, ¬_no_registers, Label::kNear); 713 __ ret(1 * kPointerSize); // Remove state. 714 715 __ bind(¬_no_registers); 716 __ mov(eax, Operand(esp, 2 * kPointerSize)); 717 __ cmp(ecx, FullCodeGenerator::TOS_REG); 718 __ j(not_equal, ¬_tos_eax, Label::kNear); 719 __ ret(2 * kPointerSize); // Remove state, eax. 720 721 __ bind(¬_tos_eax); 722 __ Abort(kNoCasesLeft); 723 } 724 725 Generate_NotifyDeoptimized(MacroAssembler * masm)726 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) { 727 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER); 728 } 729 730 Generate_NotifySoftDeoptimized(MacroAssembler * masm)731 void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) { 732 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT); 733 } 734 735 Generate_NotifyLazyDeoptimized(MacroAssembler * masm)736 void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) { 737 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY); 738 } 739 740 Generate_FunctionCall(MacroAssembler * masm)741 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { 742 Factory* factory = masm->isolate()->factory(); 743 744 // 1. Make sure we have at least one argument. 745 { Label done; 746 __ test(eax, eax); 747 __ j(not_zero, &done); 748 __ pop(ebx); 749 __ push(Immediate(factory->undefined_value())); 750 __ push(ebx); 751 __ inc(eax); 752 __ bind(&done); 753 } 754 755 // 2. Get the function to call (passed as receiver) from the stack, check 756 // if it is a function. 757 Label slow, non_function; 758 // 1 ~ return address. 759 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); 760 __ JumpIfSmi(edi, &non_function); 761 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 762 __ j(not_equal, &slow); 763 764 765 // 3a. Patch the first argument if necessary when calling a function. 766 Label shift_arguments; 767 __ Move(edx, Immediate(0)); // indicate regular JS_FUNCTION 768 { Label convert_to_object, use_global_proxy, patch_receiver; 769 // Change context eagerly in case we need the global receiver. 770 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 771 772 // Do not transform the receiver for strict mode functions. 773 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 774 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kStrictModeByteOffset), 775 1 << SharedFunctionInfo::kStrictModeBitWithinByte); 776 __ j(not_equal, &shift_arguments); 777 778 // Do not transform the receiver for natives (shared already in ebx). 779 __ test_b(FieldOperand(ebx, SharedFunctionInfo::kNativeByteOffset), 780 1 << SharedFunctionInfo::kNativeBitWithinByte); 781 __ j(not_equal, &shift_arguments); 782 783 // Compute the receiver in sloppy mode. 784 __ mov(ebx, Operand(esp, eax, times_4, 0)); // First argument. 785 786 // Call ToObject on the receiver if it is not an object, or use the 787 // global object if it is null or undefined. 788 __ JumpIfSmi(ebx, &convert_to_object); 789 __ cmp(ebx, factory->null_value()); 790 __ j(equal, &use_global_proxy); 791 __ cmp(ebx, factory->undefined_value()); 792 __ j(equal, &use_global_proxy); 793 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); 794 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx); 795 __ j(above_equal, &shift_arguments); 796 797 __ bind(&convert_to_object); 798 799 { // In order to preserve argument count. 800 FrameScope scope(masm, StackFrame::INTERNAL); 801 __ SmiTag(eax); 802 __ push(eax); 803 804 __ push(ebx); 805 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 806 __ mov(ebx, eax); 807 __ Move(edx, Immediate(0)); // restore 808 809 __ pop(eax); 810 __ SmiUntag(eax); 811 } 812 813 // Restore the function to edi. 814 __ mov(edi, Operand(esp, eax, times_4, 1 * kPointerSize)); 815 __ jmp(&patch_receiver); 816 817 __ bind(&use_global_proxy); 818 __ mov(ebx, 819 Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); 820 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset)); 821 822 __ bind(&patch_receiver); 823 __ mov(Operand(esp, eax, times_4, 0), ebx); 824 825 __ jmp(&shift_arguments); 826 } 827 828 // 3b. Check for function proxy. 829 __ bind(&slow); 830 __ Move(edx, Immediate(1)); // indicate function proxy 831 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); 832 __ j(equal, &shift_arguments); 833 __ bind(&non_function); 834 __ Move(edx, Immediate(2)); // indicate non-function 835 836 // 3c. Patch the first argument when calling a non-function. The 837 // CALL_NON_FUNCTION builtin expects the non-function callee as 838 // receiver, so overwrite the first argument which will ultimately 839 // become the receiver. 840 __ mov(Operand(esp, eax, times_4, 0), edi); 841 842 // 4. Shift arguments and return address one slot down on the stack 843 // (overwriting the original receiver). Adjust argument count to make 844 // the original first argument the new receiver. 845 __ bind(&shift_arguments); 846 { Label loop; 847 __ mov(ecx, eax); 848 __ bind(&loop); 849 __ mov(ebx, Operand(esp, ecx, times_4, 0)); 850 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); 851 __ dec(ecx); 852 __ j(not_sign, &loop); // While non-negative (to copy return address). 853 __ pop(ebx); // Discard copy of return address. 854 __ dec(eax); // One fewer argument (first argument is new receiver). 855 } 856 857 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin, 858 // or a function proxy via CALL_FUNCTION_PROXY. 859 { Label function, non_proxy; 860 __ test(edx, edx); 861 __ j(zero, &function); 862 __ Move(ebx, Immediate(0)); 863 __ cmp(edx, Immediate(1)); 864 __ j(not_equal, &non_proxy); 865 866 __ pop(edx); // return address 867 __ push(edi); // re-add proxy object as additional argument 868 __ push(edx); 869 __ inc(eax); 870 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); 871 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 872 RelocInfo::CODE_TARGET); 873 874 __ bind(&non_proxy); 875 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); 876 __ jmp(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 877 RelocInfo::CODE_TARGET); 878 __ bind(&function); 879 } 880 881 // 5b. Get the code to call from the function and check that the number of 882 // expected arguments matches what we're providing. If so, jump 883 // (tail-call) to the code in register edx without checking arguments. 884 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 885 __ mov(ebx, 886 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); 887 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset)); 888 __ SmiUntag(ebx); 889 __ cmp(eax, ebx); 890 __ j(not_equal, 891 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline()); 892 893 ParameterCount expected(0); 894 __ InvokeCode(edx, expected, expected, JUMP_FUNCTION, NullCallWrapper()); 895 } 896 897 Generate_FunctionApply(MacroAssembler * masm)898 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 899 static const int kArgumentsOffset = 2 * kPointerSize; 900 static const int kReceiverOffset = 3 * kPointerSize; 901 static const int kFunctionOffset = 4 * kPointerSize; 902 { 903 FrameScope frame_scope(masm, StackFrame::INTERNAL); 904 905 __ push(Operand(ebp, kFunctionOffset)); // push this 906 __ push(Operand(ebp, kArgumentsOffset)); // push arguments 907 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); 908 909 // Check the stack for overflow. We are not trying to catch 910 // interruptions (e.g. debug break and preemption) here, so the "real stack 911 // limit" is checked. 912 Label okay; 913 ExternalReference real_stack_limit = 914 ExternalReference::address_of_real_stack_limit(masm->isolate()); 915 __ mov(edi, Operand::StaticVariable(real_stack_limit)); 916 // Make ecx the space we have left. The stack might already be overflowed 917 // here which will cause ecx to become negative. 918 __ mov(ecx, esp); 919 __ sub(ecx, edi); 920 // Make edx the space we need for the array when it is unrolled onto the 921 // stack. 922 __ mov(edx, eax); 923 __ shl(edx, kPointerSizeLog2 - kSmiTagSize); 924 // Check if the arguments will overflow the stack. 925 __ cmp(ecx, edx); 926 __ j(greater, &okay); // Signed comparison. 927 928 // Out of stack space. 929 __ push(Operand(ebp, 4 * kPointerSize)); // push this 930 __ push(eax); 931 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); 932 __ bind(&okay); 933 // End of stack check. 934 935 // Push current index and limit. 936 const int kLimitOffset = 937 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; 938 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; 939 __ push(eax); // limit 940 __ push(Immediate(0)); // index 941 942 // Get the receiver. 943 __ mov(ebx, Operand(ebp, kReceiverOffset)); 944 945 // Check that the function is a JS function (otherwise it must be a proxy). 946 Label push_receiver, use_global_proxy; 947 __ mov(edi, Operand(ebp, kFunctionOffset)); 948 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 949 __ j(not_equal, &push_receiver); 950 951 // Change context eagerly to get the right global object if necessary. 952 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 953 954 // Compute the receiver. 955 // Do not transform the receiver for strict mode functions. 956 Label call_to_object; 957 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 958 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrictModeByteOffset), 959 1 << SharedFunctionInfo::kStrictModeBitWithinByte); 960 __ j(not_equal, &push_receiver); 961 962 Factory* factory = masm->isolate()->factory(); 963 964 // Do not transform the receiver for natives (shared already in ecx). 965 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kNativeByteOffset), 966 1 << SharedFunctionInfo::kNativeBitWithinByte); 967 __ j(not_equal, &push_receiver); 968 969 // Compute the receiver in sloppy mode. 970 // Call ToObject on the receiver if it is not an object, or use the 971 // global object if it is null or undefined. 972 __ JumpIfSmi(ebx, &call_to_object); 973 __ cmp(ebx, factory->null_value()); 974 __ j(equal, &use_global_proxy); 975 __ cmp(ebx, factory->undefined_value()); 976 __ j(equal, &use_global_proxy); 977 STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); 978 __ CmpObjectType(ebx, FIRST_SPEC_OBJECT_TYPE, ecx); 979 __ j(above_equal, &push_receiver); 980 981 __ bind(&call_to_object); 982 __ push(ebx); 983 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 984 __ mov(ebx, eax); 985 __ jmp(&push_receiver); 986 987 __ bind(&use_global_proxy); 988 __ mov(ebx, 989 Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); 990 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalProxyOffset)); 991 992 // Push the receiver. 993 __ bind(&push_receiver); 994 __ push(ebx); 995 996 // Copy all arguments from the array to the stack. 997 Label entry, loop; 998 Register receiver = LoadDescriptor::ReceiverRegister(); 999 Register key = LoadDescriptor::NameRegister(); 1000 __ mov(key, Operand(ebp, kIndexOffset)); 1001 __ jmp(&entry); 1002 __ bind(&loop); 1003 __ mov(receiver, Operand(ebp, kArgumentsOffset)); // load arguments 1004 1005 // Use inline caching to speed up access to arguments. 1006 if (FLAG_vector_ics) { 1007 __ mov(VectorLoadICDescriptor::SlotRegister(), 1008 Immediate(Smi::FromInt(0))); 1009 } 1010 Handle<Code> ic = CodeFactory::KeyedLoadIC(masm->isolate()).code(); 1011 __ call(ic, RelocInfo::CODE_TARGET); 1012 // It is important that we do not have a test instruction after the 1013 // call. A test instruction after the call is used to indicate that 1014 // we have generated an inline version of the keyed load. In this 1015 // case, we know that we are not generating a test instruction next. 1016 1017 // Push the nth argument. 1018 __ push(eax); 1019 1020 // Update the index on the stack and in register key. 1021 __ mov(key, Operand(ebp, kIndexOffset)); 1022 __ add(key, Immediate(1 << kSmiTagSize)); 1023 __ mov(Operand(ebp, kIndexOffset), key); 1024 1025 __ bind(&entry); 1026 __ cmp(key, Operand(ebp, kLimitOffset)); 1027 __ j(not_equal, &loop); 1028 1029 // Call the function. 1030 Label call_proxy; 1031 ParameterCount actual(eax); 1032 __ Move(eax, key); 1033 __ SmiUntag(eax); 1034 __ mov(edi, Operand(ebp, kFunctionOffset)); 1035 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 1036 __ j(not_equal, &call_proxy); 1037 __ InvokeFunction(edi, actual, CALL_FUNCTION, NullCallWrapper()); 1038 1039 frame_scope.GenerateLeaveFrame(); 1040 __ ret(3 * kPointerSize); // remove this, receiver, and arguments 1041 1042 // Call the function proxy. 1043 __ bind(&call_proxy); 1044 __ push(edi); // add function proxy as last argument 1045 __ inc(eax); 1046 __ Move(ebx, Immediate(0)); 1047 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); 1048 __ call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), 1049 RelocInfo::CODE_TARGET); 1050 1051 // Leave internal frame. 1052 } 1053 __ ret(3 * kPointerSize); // remove this, receiver, and arguments 1054 } 1055 1056 Generate_InternalArrayCode(MacroAssembler * masm)1057 void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { 1058 // ----------- S t a t e ------------- 1059 // -- eax : argc 1060 // -- esp[0] : return address 1061 // -- esp[4] : last argument 1062 // ----------------------------------- 1063 Label generic_array_code; 1064 1065 // Get the InternalArray function. 1066 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi); 1067 1068 if (FLAG_debug_code) { 1069 // Initial map for the builtin InternalArray function should be a map. 1070 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 1071 // Will both indicate a NULL and a Smi. 1072 __ test(ebx, Immediate(kSmiTagMask)); 1073 __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction); 1074 __ CmpObjectType(ebx, MAP_TYPE, ecx); 1075 __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction); 1076 } 1077 1078 // Run the native code for the InternalArray function called as a normal 1079 // function. 1080 // tail call a stub 1081 InternalArrayConstructorStub stub(masm->isolate()); 1082 __ TailCallStub(&stub); 1083 } 1084 1085 Generate_ArrayCode(MacroAssembler * masm)1086 void Builtins::Generate_ArrayCode(MacroAssembler* masm) { 1087 // ----------- S t a t e ------------- 1088 // -- eax : argc 1089 // -- esp[0] : return address 1090 // -- esp[4] : last argument 1091 // ----------------------------------- 1092 Label generic_array_code; 1093 1094 // Get the Array function. 1095 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi); 1096 1097 if (FLAG_debug_code) { 1098 // Initial map for the builtin Array function should be a map. 1099 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 1100 // Will both indicate a NULL and a Smi. 1101 __ test(ebx, Immediate(kSmiTagMask)); 1102 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction); 1103 __ CmpObjectType(ebx, MAP_TYPE, ecx); 1104 __ Assert(equal, kUnexpectedInitialMapForArrayFunction); 1105 } 1106 1107 // Run the native code for the Array function called as a normal function. 1108 // tail call a stub 1109 __ mov(ebx, masm->isolate()->factory()->undefined_value()); 1110 ArrayConstructorStub stub(masm->isolate()); 1111 __ TailCallStub(&stub); 1112 } 1113 1114 Generate_StringConstructCode(MacroAssembler * masm)1115 void Builtins::Generate_StringConstructCode(MacroAssembler* masm) { 1116 // ----------- S t a t e ------------- 1117 // -- eax : number of arguments 1118 // -- edi : constructor function 1119 // -- esp[0] : return address 1120 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1121 // -- esp[(argc + 1) * 4] : receiver 1122 // ----------------------------------- 1123 Counters* counters = masm->isolate()->counters(); 1124 __ IncrementCounter(counters->string_ctor_calls(), 1); 1125 1126 if (FLAG_debug_code) { 1127 __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, ecx); 1128 __ cmp(edi, ecx); 1129 __ Assert(equal, kUnexpectedStringFunction); 1130 } 1131 1132 // Load the first argument into eax and get rid of the rest 1133 // (including the receiver). 1134 Label no_arguments; 1135 __ test(eax, eax); 1136 __ j(zero, &no_arguments); 1137 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0)); 1138 __ pop(ecx); 1139 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); 1140 __ push(ecx); 1141 __ mov(eax, ebx); 1142 1143 // Lookup the argument in the number to string cache. 1144 Label not_cached, argument_is_string; 1145 __ LookupNumberStringCache(eax, // Input. 1146 ebx, // Result. 1147 ecx, // Scratch 1. 1148 edx, // Scratch 2. 1149 ¬_cached); 1150 __ IncrementCounter(counters->string_ctor_cached_number(), 1); 1151 __ bind(&argument_is_string); 1152 // ----------- S t a t e ------------- 1153 // -- ebx : argument converted to string 1154 // -- edi : constructor function 1155 // -- esp[0] : return address 1156 // ----------------------------------- 1157 1158 // Allocate a JSValue and put the tagged pointer into eax. 1159 Label gc_required; 1160 __ Allocate(JSValue::kSize, 1161 eax, // Result. 1162 ecx, // New allocation top (we ignore it). 1163 no_reg, 1164 &gc_required, 1165 TAG_OBJECT); 1166 1167 // Set the map. 1168 __ LoadGlobalFunctionInitialMap(edi, ecx); 1169 if (FLAG_debug_code) { 1170 __ cmpb(FieldOperand(ecx, Map::kInstanceSizeOffset), 1171 JSValue::kSize >> kPointerSizeLog2); 1172 __ Assert(equal, kUnexpectedStringWrapperInstanceSize); 1173 __ cmpb(FieldOperand(ecx, Map::kUnusedPropertyFieldsOffset), 0); 1174 __ Assert(equal, kUnexpectedUnusedPropertiesOfStringWrapper); 1175 } 1176 __ mov(FieldOperand(eax, HeapObject::kMapOffset), ecx); 1177 1178 // Set properties and elements. 1179 Factory* factory = masm->isolate()->factory(); 1180 __ Move(ecx, Immediate(factory->empty_fixed_array())); 1181 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx); 1182 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ecx); 1183 1184 // Set the value. 1185 __ mov(FieldOperand(eax, JSValue::kValueOffset), ebx); 1186 1187 // Ensure the object is fully initialized. 1188 STATIC_ASSERT(JSValue::kSize == 4 * kPointerSize); 1189 1190 // We're done. Return. 1191 __ ret(0); 1192 1193 // The argument was not found in the number to string cache. Check 1194 // if it's a string already before calling the conversion builtin. 1195 Label convert_argument; 1196 __ bind(¬_cached); 1197 STATIC_ASSERT(kSmiTag == 0); 1198 __ JumpIfSmi(eax, &convert_argument); 1199 Condition is_string = masm->IsObjectStringType(eax, ebx, ecx); 1200 __ j(NegateCondition(is_string), &convert_argument); 1201 __ mov(ebx, eax); 1202 __ IncrementCounter(counters->string_ctor_string_value(), 1); 1203 __ jmp(&argument_is_string); 1204 1205 // Invoke the conversion builtin and put the result into ebx. 1206 __ bind(&convert_argument); 1207 __ IncrementCounter(counters->string_ctor_conversions(), 1); 1208 { 1209 FrameScope scope(masm, StackFrame::INTERNAL); 1210 __ push(edi); // Preserve the function. 1211 __ push(eax); 1212 __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION); 1213 __ pop(edi); 1214 } 1215 __ mov(ebx, eax); 1216 __ jmp(&argument_is_string); 1217 1218 // Load the empty string into ebx, remove the receiver from the 1219 // stack, and jump back to the case where the argument is a string. 1220 __ bind(&no_arguments); 1221 __ Move(ebx, Immediate(factory->empty_string())); 1222 __ pop(ecx); 1223 __ lea(esp, Operand(esp, kPointerSize)); 1224 __ push(ecx); 1225 __ jmp(&argument_is_string); 1226 1227 // At this point the argument is already a string. Call runtime to 1228 // create a string wrapper. 1229 __ bind(&gc_required); 1230 __ IncrementCounter(counters->string_ctor_gc_required(), 1); 1231 { 1232 FrameScope scope(masm, StackFrame::INTERNAL); 1233 __ push(ebx); 1234 __ CallRuntime(Runtime::kNewStringWrapper, 1); 1235 } 1236 __ ret(0); 1237 } 1238 1239 ArgumentsAdaptorStackCheck(MacroAssembler * masm,Label * stack_overflow)1240 static void ArgumentsAdaptorStackCheck(MacroAssembler* masm, 1241 Label* stack_overflow) { 1242 // ----------- S t a t e ------------- 1243 // -- eax : actual number of arguments 1244 // -- ebx : expected number of arguments 1245 // -- edi : function (passed through to callee) 1246 // ----------------------------------- 1247 // Check the stack for overflow. We are not trying to catch 1248 // interruptions (e.g. debug break and preemption) here, so the "real stack 1249 // limit" is checked. 1250 ExternalReference real_stack_limit = 1251 ExternalReference::address_of_real_stack_limit(masm->isolate()); 1252 __ mov(edx, Operand::StaticVariable(real_stack_limit)); 1253 // Make ecx the space we have left. The stack might already be overflowed 1254 // here which will cause ecx to become negative. 1255 __ mov(ecx, esp); 1256 __ sub(ecx, edx); 1257 // Make edx the space we need for the array when it is unrolled onto the 1258 // stack. 1259 __ mov(edx, ebx); 1260 __ shl(edx, kPointerSizeLog2); 1261 // Check if the arguments will overflow the stack. 1262 __ cmp(ecx, edx); 1263 __ j(less_equal, stack_overflow); // Signed comparison. 1264 } 1265 1266 EnterArgumentsAdaptorFrame(MacroAssembler * masm)1267 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { 1268 __ push(ebp); 1269 __ mov(ebp, esp); 1270 1271 // Store the arguments adaptor context sentinel. 1272 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 1273 1274 // Push the function on the stack. 1275 __ push(edi); 1276 1277 // Preserve the number of arguments on the stack. Must preserve eax, 1278 // ebx and ecx because these registers are used when copying the 1279 // arguments and the receiver. 1280 STATIC_ASSERT(kSmiTagSize == 1); 1281 __ lea(edi, Operand(eax, eax, times_1, kSmiTag)); 1282 __ push(edi); 1283 } 1284 1285 LeaveArgumentsAdaptorFrame(MacroAssembler * masm)1286 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { 1287 // Retrieve the number of arguments from the stack. 1288 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset)); 1289 1290 // Leave the frame. 1291 __ leave(); 1292 1293 // Remove caller arguments from the stack. 1294 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 1295 __ pop(ecx); 1296 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver 1297 __ push(ecx); 1298 } 1299 1300 Generate_ArgumentsAdaptorTrampoline(MacroAssembler * masm)1301 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { 1302 // ----------- S t a t e ------------- 1303 // -- eax : actual number of arguments 1304 // -- ebx : expected number of arguments 1305 // -- edi : function (passed through to callee) 1306 // ----------------------------------- 1307 1308 Label invoke, dont_adapt_arguments; 1309 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1); 1310 1311 Label stack_overflow; 1312 ArgumentsAdaptorStackCheck(masm, &stack_overflow); 1313 1314 Label enough, too_few; 1315 __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset)); 1316 __ cmp(eax, ebx); 1317 __ j(less, &too_few); 1318 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); 1319 __ j(equal, &dont_adapt_arguments); 1320 1321 { // Enough parameters: Actual >= expected. 1322 __ bind(&enough); 1323 EnterArgumentsAdaptorFrame(masm); 1324 1325 // Copy receiver and all expected arguments. 1326 const int offset = StandardFrameConstants::kCallerSPOffset; 1327 __ lea(eax, Operand(ebp, eax, times_4, offset)); 1328 __ mov(edi, -1); // account for receiver 1329 1330 Label copy; 1331 __ bind(©); 1332 __ inc(edi); 1333 __ push(Operand(eax, 0)); 1334 __ sub(eax, Immediate(kPointerSize)); 1335 __ cmp(edi, ebx); 1336 __ j(less, ©); 1337 __ jmp(&invoke); 1338 } 1339 1340 { // Too few parameters: Actual < expected. 1341 __ bind(&too_few); 1342 EnterArgumentsAdaptorFrame(masm); 1343 1344 // Copy receiver and all actual arguments. 1345 const int offset = StandardFrameConstants::kCallerSPOffset; 1346 __ lea(edi, Operand(ebp, eax, times_4, offset)); 1347 // ebx = expected - actual. 1348 __ sub(ebx, eax); 1349 // eax = -actual - 1 1350 __ neg(eax); 1351 __ sub(eax, Immediate(1)); 1352 1353 Label copy; 1354 __ bind(©); 1355 __ inc(eax); 1356 __ push(Operand(edi, 0)); 1357 __ sub(edi, Immediate(kPointerSize)); 1358 __ test(eax, eax); 1359 __ j(not_zero, ©); 1360 1361 // Fill remaining expected arguments with undefined values. 1362 Label fill; 1363 __ bind(&fill); 1364 __ inc(eax); 1365 __ push(Immediate(masm->isolate()->factory()->undefined_value())); 1366 __ cmp(eax, ebx); 1367 __ j(less, &fill); 1368 } 1369 1370 // Call the entry point. 1371 __ bind(&invoke); 1372 // Restore function pointer. 1373 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 1374 __ call(edx); 1375 1376 // Store offset of return address for deoptimizer. 1377 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset()); 1378 1379 // Leave frame and return. 1380 LeaveArgumentsAdaptorFrame(masm); 1381 __ ret(0); 1382 1383 // ------------------------------------------- 1384 // Dont adapt arguments. 1385 // ------------------------------------------- 1386 __ bind(&dont_adapt_arguments); 1387 __ jmp(edx); 1388 1389 __ bind(&stack_overflow); 1390 { 1391 FrameScope frame(masm, StackFrame::MANUAL); 1392 EnterArgumentsAdaptorFrame(masm); 1393 __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION); 1394 __ int3(); 1395 } 1396 } 1397 1398 Generate_OnStackReplacement(MacroAssembler * masm)1399 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) { 1400 // Lookup the function in the JavaScript frame. 1401 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 1402 { 1403 FrameScope scope(masm, StackFrame::INTERNAL); 1404 // Pass function as argument. 1405 __ push(eax); 1406 __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1); 1407 } 1408 1409 Label skip; 1410 // If the code object is null, just return to the unoptimized code. 1411 __ cmp(eax, Immediate(0)); 1412 __ j(not_equal, &skip, Label::kNear); 1413 __ ret(0); 1414 1415 __ bind(&skip); 1416 1417 // Load deoptimization data from the code object. 1418 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag)); 1419 1420 // Load the OSR entrypoint offset from the deoptimization data. 1421 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt( 1422 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag)); 1423 __ SmiUntag(ebx); 1424 1425 // Compute the target address = code_obj + header_size + osr_offset 1426 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag)); 1427 1428 // Overwrite the return address on the stack. 1429 __ mov(Operand(esp, 0), eax); 1430 1431 // And "return" to the OSR entry point of the function. 1432 __ ret(0); 1433 } 1434 1435 Generate_OsrAfterStackCheck(MacroAssembler * masm)1436 void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) { 1437 // We check the stack limit as indicator that recompilation might be done. 1438 Label ok; 1439 ExternalReference stack_limit = 1440 ExternalReference::address_of_stack_limit(masm->isolate()); 1441 __ cmp(esp, Operand::StaticVariable(stack_limit)); 1442 __ j(above_equal, &ok, Label::kNear); 1443 { 1444 FrameScope scope(masm, StackFrame::INTERNAL); 1445 __ CallRuntime(Runtime::kStackGuard, 0); 1446 } 1447 __ jmp(masm->isolate()->builtins()->OnStackReplacement(), 1448 RelocInfo::CODE_TARGET); 1449 1450 __ bind(&ok); 1451 __ ret(0); 1452 } 1453 1454 #undef __ 1455 } 1456 } // namespace v8::internal 1457 1458 #endif // V8_TARGET_ARCH_X87 1459