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