builtins-ia32.cc revision a7e24c173cf37484693b9abb38e494fa7bd7baeb
1// Copyright 2006-2009 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#include "codegen-inl.h" 31 32namespace v8 { 33namespace internal { 34 35 36#define __ ACCESS_MASM(masm) 37 38 39void Builtins::Generate_Adaptor(MacroAssembler* masm, CFunctionId id) { 40 // TODO(428): Don't pass the function in a static variable. 41 ExternalReference passed = ExternalReference::builtin_passed_function(); 42 __ mov(Operand::StaticVariable(passed), edi); 43 44 // The actual argument count has already been loaded into register 45 // eax, but JumpToRuntime expects eax to contain the number of 46 // arguments including the receiver. 47 __ inc(eax); 48 __ JumpToRuntime(ExternalReference(id)); 49} 50 51 52void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { 53 // ----------- S t a t e ------------- 54 // -- eax: number of arguments 55 // -- edi: constructor function 56 // ----------------------------------- 57 58 Label non_function_call; 59 // Check that function is not a smi. 60 __ test(edi, Immediate(kSmiTagMask)); 61 __ j(zero, &non_function_call); 62 // Check that function is a JSFunction. 63 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 64 __ j(not_equal, &non_function_call); 65 66 // Jump to the function-specific construct stub. 67 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 68 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset)); 69 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); 70 __ jmp(Operand(ebx)); 71 72 // edi: called object 73 // eax: number of arguments 74 __ bind(&non_function_call); 75 76 // Set expected number of arguments to zero (not changing eax). 77 __ Set(ebx, Immediate(0)); 78 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); 79 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 80 RelocInfo::CODE_TARGET); 81} 82 83 84void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { 85 // Enter a construct frame. 86 __ EnterConstructFrame(); 87 88 // Store a smi-tagged arguments count on the stack. 89 __ shl(eax, kSmiTagSize); 90 __ push(eax); 91 92 // Push the function to invoke on the stack. 93 __ push(edi); 94 95 // Try to allocate the object without transitioning into C code. If any of the 96 // preconditions is not met, the code bails out to the runtime call. 97 Label rt_call, allocated; 98 if (FLAG_inline_new) { 99 Label undo_allocation; 100#ifdef ENABLE_DEBUGGER_SUPPORT 101 ExternalReference debug_step_in_fp = 102 ExternalReference::debug_step_in_fp_address(); 103 __ cmp(Operand::StaticVariable(debug_step_in_fp), Immediate(0)); 104 __ j(not_equal, &rt_call); 105#endif 106 107 // Verified that the constructor is a JSFunction. 108 // Load the initial map and verify that it is in fact a map. 109 // edi: constructor 110 __ mov(eax, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 111 // Will both indicate a NULL and a Smi 112 __ test(eax, Immediate(kSmiTagMask)); 113 __ j(zero, &rt_call); 114 // edi: constructor 115 // eax: initial map (if proven valid below) 116 __ CmpObjectType(eax, MAP_TYPE, ebx); 117 __ j(not_equal, &rt_call); 118 119 // Check that the constructor is not constructing a JSFunction (see comments 120 // in Runtime_NewObject in runtime.cc). In which case the initial map's 121 // instance type would be JS_FUNCTION_TYPE. 122 // edi: constructor 123 // eax: initial map 124 __ CmpInstanceType(eax, JS_FUNCTION_TYPE); 125 __ j(equal, &rt_call); 126 127 // Now allocate the JSObject on the heap. 128 // edi: constructor 129 // eax: initial map 130 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset)); 131 __ shl(edi, kPointerSizeLog2); 132 __ AllocateInNewSpace(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); 133 // Allocated the JSObject, now initialize the fields. 134 // eax: initial map 135 // ebx: JSObject 136 // edi: start of next object 137 __ mov(Operand(ebx, JSObject::kMapOffset), eax); 138 __ mov(ecx, Factory::empty_fixed_array()); 139 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx); 140 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx); 141 // Set extra fields in the newly allocated object. 142 // eax: initial map 143 // ebx: JSObject 144 // edi: start of next object 145 { Label loop, entry; 146 __ mov(edx, Factory::undefined_value()); 147 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize)); 148 __ jmp(&entry); 149 __ bind(&loop); 150 __ mov(Operand(ecx, 0), edx); 151 __ add(Operand(ecx), Immediate(kPointerSize)); 152 __ bind(&entry); 153 __ cmp(ecx, Operand(edi)); 154 __ j(less, &loop); 155 } 156 157 // Add the object tag to make the JSObject real, so that we can continue and 158 // jump into the continuation code at any time from now on. Any failures 159 // need to undo the allocation, so that the heap is in a consistent state 160 // and verifiable. 161 // eax: initial map 162 // ebx: JSObject 163 // edi: start of next object 164 __ or_(Operand(ebx), Immediate(kHeapObjectTag)); 165 166 // Check if a non-empty properties array is needed. 167 // Allocate and initialize a FixedArray if it is. 168 // eax: initial map 169 // ebx: JSObject 170 // edi: start of next object 171 // Calculate the total number of properties described by the map. 172 __ movzx_b(edx, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset)); 173 __ movzx_b(ecx, FieldOperand(eax, Map::kPreAllocatedPropertyFieldsOffset)); 174 __ add(edx, Operand(ecx)); 175 // Calculate unused properties past the end of the in-object properties. 176 __ movzx_b(ecx, FieldOperand(eax, Map::kInObjectPropertiesOffset)); 177 __ sub(edx, Operand(ecx)); 178 // Done if no extra properties are to be allocated. 179 __ j(zero, &allocated); 180 __ Assert(positive, "Property allocation count failed."); 181 182 // Scale the number of elements by pointer size and add the header for 183 // FixedArrays to the start of the next object calculation from above. 184 // ebx: JSObject 185 // edi: start of next object (will be start of FixedArray) 186 // edx: number of elements in properties array 187 __ AllocateInNewSpace(FixedArray::kHeaderSize, 188 times_pointer_size, 189 edx, 190 edi, 191 ecx, 192 no_reg, 193 &undo_allocation, 194 RESULT_CONTAINS_TOP); 195 196 // Initialize the FixedArray. 197 // ebx: JSObject 198 // edi: FixedArray 199 // edx: number of elements 200 // ecx: start of next object 201 __ mov(eax, Factory::fixed_array_map()); 202 __ mov(Operand(edi, JSObject::kMapOffset), eax); // setup the map 203 __ mov(Operand(edi, Array::kLengthOffset), edx); // and length 204 205 // Initialize the fields to undefined. 206 // ebx: JSObject 207 // edi: FixedArray 208 // ecx: start of next object 209 { Label loop, entry; 210 __ mov(edx, Factory::undefined_value()); 211 __ lea(eax, Operand(edi, FixedArray::kHeaderSize)); 212 __ jmp(&entry); 213 __ bind(&loop); 214 __ mov(Operand(eax, 0), edx); 215 __ add(Operand(eax), Immediate(kPointerSize)); 216 __ bind(&entry); 217 __ cmp(eax, Operand(ecx)); 218 __ j(below, &loop); 219 } 220 221 // Store the initialized FixedArray into the properties field of 222 // the JSObject 223 // ebx: JSObject 224 // edi: FixedArray 225 __ or_(Operand(edi), Immediate(kHeapObjectTag)); // add the heap tag 226 __ mov(FieldOperand(ebx, JSObject::kPropertiesOffset), edi); 227 228 229 // Continue with JSObject being successfully allocated 230 // ebx: JSObject 231 __ jmp(&allocated); 232 233 // Undo the setting of the new top so that the heap is verifiable. For 234 // example, the map's unused properties potentially do not match the 235 // allocated objects unused properties. 236 // ebx: JSObject (previous new top) 237 __ bind(&undo_allocation); 238 __ UndoAllocationInNewSpace(ebx); 239 } 240 241 // Allocate the new receiver object using the runtime call. 242 __ bind(&rt_call); 243 // Must restore edi (constructor) before calling runtime. 244 __ mov(edi, Operand(esp, 0)); 245 // edi: function (constructor) 246 __ push(edi); 247 __ CallRuntime(Runtime::kNewObject, 1); 248 __ mov(ebx, Operand(eax)); // store result in ebx 249 250 // New object allocated. 251 // ebx: newly allocated object 252 __ bind(&allocated); 253 // Retrieve the function from the stack. 254 __ pop(edi); 255 256 // Retrieve smi-tagged arguments count from the stack. 257 __ mov(eax, Operand(esp, 0)); 258 __ shr(eax, kSmiTagSize); 259 260 // Push the allocated receiver to the stack. We need two copies 261 // because we may have to return the original one and the calling 262 // conventions dictate that the called function pops the receiver. 263 __ push(ebx); 264 __ push(ebx); 265 266 // Setup pointer to last argument. 267 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); 268 269 // Copy arguments and receiver to the expression stack. 270 Label loop, entry; 271 __ mov(ecx, Operand(eax)); 272 __ jmp(&entry); 273 __ bind(&loop); 274 __ push(Operand(ebx, ecx, times_4, 0)); 275 __ bind(&entry); 276 __ dec(ecx); 277 __ j(greater_equal, &loop); 278 279 // Call the function. 280 ParameterCount actual(eax); 281 __ InvokeFunction(edi, actual, CALL_FUNCTION); 282 283 // Restore context from the frame. 284 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 285 286 // If the result is an object (in the ECMA sense), we should get rid 287 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 288 // on page 74. 289 Label use_receiver, exit; 290 291 // If the result is a smi, it is *not* an object in the ECMA sense. 292 __ test(eax, Immediate(kSmiTagMask)); 293 __ j(zero, &use_receiver, not_taken); 294 295 // If the type of the result (stored in its map) is less than 296 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense. 297 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 298 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 299 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); 300 __ j(greater_equal, &exit, not_taken); 301 302 // Throw away the result of the constructor invocation and use the 303 // on-stack receiver as the result. 304 __ bind(&use_receiver); 305 __ mov(eax, Operand(esp, 0)); 306 307 // Restore the arguments count and leave the construct frame. 308 __ bind(&exit); 309 __ mov(ebx, Operand(esp, kPointerSize)); // get arguments count 310 __ LeaveConstructFrame(); 311 312 // Remove caller arguments from the stack and return. 313 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 314 __ pop(ecx); 315 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver 316 __ push(ecx); 317 __ IncrementCounter(&Counters::constructed_objects, 1); 318 __ ret(0); 319} 320 321 322static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, 323 bool is_construct) { 324 // Clear the context before we push it when entering the JS frame. 325 __ xor_(esi, Operand(esi)); // clear esi 326 327 // Enter an internal frame. 328 __ EnterInternalFrame(); 329 330 // Load the previous frame pointer (ebx) to access C arguments 331 __ mov(ebx, Operand(ebp, 0)); 332 333 // Get the function from the frame and setup the context. 334 __ mov(ecx, Operand(ebx, EntryFrameConstants::kFunctionArgOffset)); 335 __ mov(esi, FieldOperand(ecx, JSFunction::kContextOffset)); 336 337 // Push the function and the receiver onto the stack. 338 __ push(ecx); 339 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset)); 340 341 // Load the number of arguments and setup pointer to the arguments. 342 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset)); 343 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset)); 344 345 // Copy arguments to the stack in a loop. 346 Label loop, entry; 347 __ xor_(ecx, Operand(ecx)); // clear ecx 348 __ jmp(&entry); 349 __ bind(&loop); 350 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv 351 __ push(Operand(edx, 0)); // dereference handle 352 __ inc(Operand(ecx)); 353 __ bind(&entry); 354 __ cmp(ecx, Operand(eax)); 355 __ j(not_equal, &loop); 356 357 // Get the function from the stack and call it. 358 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); // +1 ~ receiver 359 360 // Invoke the code. 361 if (is_construct) { 362 __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), 363 RelocInfo::CODE_TARGET); 364 } else { 365 ParameterCount actual(eax); 366 __ InvokeFunction(edi, actual, CALL_FUNCTION); 367 } 368 369 // Exit the JS frame. Notice that this also removes the empty 370 // context and the function left on the stack by the code 371 // invocation. 372 __ LeaveInternalFrame(); 373 __ ret(1 * kPointerSize); // remove receiver 374} 375 376 377void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { 378 Generate_JSEntryTrampolineHelper(masm, false); 379} 380 381 382void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { 383 Generate_JSEntryTrampolineHelper(masm, true); 384} 385 386 387void Builtins::Generate_FunctionCall(MacroAssembler* masm) { 388 // 1. Make sure we have at least one argument. 389 { Label done; 390 __ test(eax, Operand(eax)); 391 __ j(not_zero, &done, taken); 392 __ pop(ebx); 393 __ push(Immediate(Factory::undefined_value())); 394 __ push(ebx); 395 __ inc(eax); 396 __ bind(&done); 397 } 398 399 // 2. Get the function to call from the stack. 400 { Label done, non_function, function; 401 // +1 ~ return address. 402 __ mov(edi, Operand(esp, eax, times_4, +1 * kPointerSize)); 403 __ test(edi, Immediate(kSmiTagMask)); 404 __ j(zero, &non_function, not_taken); 405 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 406 __ j(equal, &function, taken); 407 408 // Non-function called: Clear the function to force exception. 409 __ bind(&non_function); 410 __ xor_(edi, Operand(edi)); 411 __ jmp(&done); 412 413 // Function called: Change context eagerly to get the right global object. 414 __ bind(&function); 415 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 416 417 __ bind(&done); 418 } 419 420 // 3. Make sure first argument is an object; convert if necessary. 421 { Label call_to_object, use_global_receiver, patch_receiver, done; 422 __ mov(ebx, Operand(esp, eax, times_4, 0)); 423 424 __ test(ebx, Immediate(kSmiTagMask)); 425 __ j(zero, &call_to_object); 426 427 __ cmp(ebx, Factory::null_value()); 428 __ j(equal, &use_global_receiver); 429 __ cmp(ebx, Factory::undefined_value()); 430 __ j(equal, &use_global_receiver); 431 432 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); 433 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 434 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); 435 __ j(less, &call_to_object); 436 __ cmp(ecx, LAST_JS_OBJECT_TYPE); 437 __ j(less_equal, &done); 438 439 __ bind(&call_to_object); 440 __ EnterInternalFrame(); // preserves eax, ebx, edi 441 442 // Store the arguments count on the stack (smi tagged). 443 ASSERT(kSmiTag == 0); 444 __ shl(eax, kSmiTagSize); 445 __ push(eax); 446 447 __ push(edi); // save edi across the call 448 __ push(ebx); 449 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 450 __ mov(ebx, eax); 451 __ pop(edi); // restore edi after the call 452 453 // Get the arguments count and untag it. 454 __ pop(eax); 455 __ shr(eax, kSmiTagSize); 456 457 __ LeaveInternalFrame(); 458 __ jmp(&patch_receiver); 459 460 // Use the global receiver object from the called function as the receiver. 461 __ bind(&use_global_receiver); 462 const int kGlobalIndex = 463 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 464 __ mov(ebx, FieldOperand(esi, kGlobalIndex)); 465 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); 466 467 __ bind(&patch_receiver); 468 __ mov(Operand(esp, eax, times_4, 0), ebx); 469 470 __ bind(&done); 471 } 472 473 // 4. Shift stuff one slot down the stack. 474 { Label loop; 475 __ lea(ecx, Operand(eax, +1)); // +1 ~ copy receiver too 476 __ bind(&loop); 477 __ mov(ebx, Operand(esp, ecx, times_4, 0)); 478 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); 479 __ dec(ecx); 480 __ j(not_zero, &loop); 481 } 482 483 // 5. Remove TOS (copy of last arguments), but keep return address. 484 __ pop(ebx); 485 __ pop(ecx); 486 __ push(ebx); 487 __ dec(eax); 488 489 // 6. Check that function really was a function and get the code to 490 // call from the function and check that the number of expected 491 // arguments matches what we're providing. 492 { Label invoke; 493 __ test(edi, Operand(edi)); 494 __ j(not_zero, &invoke, taken); 495 __ xor_(ebx, Operand(ebx)); 496 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); 497 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 498 RelocInfo::CODE_TARGET); 499 500 __ bind(&invoke); 501 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 502 __ mov(ebx, 503 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); 504 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); 505 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); 506 __ cmp(eax, Operand(ebx)); 507 __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline))); 508 } 509 510 // 7. Jump (tail-call) to the code in register edx without checking arguments. 511 ParameterCount expected(0); 512 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION); 513} 514 515 516void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 517 __ EnterInternalFrame(); 518 519 __ push(Operand(ebp, 4 * kPointerSize)); // push this 520 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments 521 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); 522 523 if (FLAG_check_stack) { 524 // We need to catch preemptions right here, otherwise an unlucky preemption 525 // could show up as a failed apply. 526 ExternalReference stack_guard_limit = 527 ExternalReference::address_of_stack_guard_limit(); 528 Label retry_preemption; 529 Label no_preemption; 530 __ bind(&retry_preemption); 531 __ mov(edi, Operand::StaticVariable(stack_guard_limit)); 532 __ cmp(esp, Operand(edi)); 533 __ j(above, &no_preemption, taken); 534 535 // Preemption! 536 // Because builtins always remove the receiver from the stack, we 537 // have to fake one to avoid underflowing the stack. 538 __ push(eax); 539 __ push(Immediate(Smi::FromInt(0))); 540 541 // Do call to runtime routine. 542 __ CallRuntime(Runtime::kStackGuard, 1); 543 __ pop(eax); 544 __ jmp(&retry_preemption); 545 546 __ bind(&no_preemption); 547 548 Label okay; 549 // Make ecx the space we have left. 550 __ mov(ecx, Operand(esp)); 551 __ sub(ecx, Operand(edi)); 552 // Make edx the space we need for the array when it is unrolled onto the 553 // stack. 554 __ mov(edx, Operand(eax)); 555 __ shl(edx, kPointerSizeLog2 - kSmiTagSize); 556 __ cmp(ecx, Operand(edx)); 557 __ j(greater, &okay, taken); 558 559 // Too bad: Out of stack space. 560 __ push(Operand(ebp, 4 * kPointerSize)); // push this 561 __ push(eax); 562 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); 563 __ bind(&okay); 564 } 565 566 // Push current index and limit. 567 const int kLimitOffset = 568 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; 569 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; 570 __ push(eax); // limit 571 __ push(Immediate(0)); // index 572 573 // Change context eagerly to get the right global object if 574 // necessary. 575 __ mov(edi, Operand(ebp, 4 * kPointerSize)); 576 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 577 578 // Compute the receiver. 579 Label call_to_object, use_global_receiver, push_receiver; 580 __ mov(ebx, Operand(ebp, 3 * kPointerSize)); 581 __ test(ebx, Immediate(kSmiTagMask)); 582 __ j(zero, &call_to_object); 583 __ cmp(ebx, Factory::null_value()); 584 __ j(equal, &use_global_receiver); 585 __ cmp(ebx, Factory::undefined_value()); 586 __ j(equal, &use_global_receiver); 587 588 // If given receiver is already a JavaScript object then there's no 589 // reason for converting it. 590 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); 591 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 592 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); 593 __ j(less, &call_to_object); 594 __ cmp(ecx, LAST_JS_OBJECT_TYPE); 595 __ j(less_equal, &push_receiver); 596 597 // Convert the receiver to an object. 598 __ bind(&call_to_object); 599 __ push(ebx); 600 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 601 __ mov(ebx, Operand(eax)); 602 __ jmp(&push_receiver); 603 604 // Use the current global receiver object as the receiver. 605 __ bind(&use_global_receiver); 606 const int kGlobalOffset = 607 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 608 __ mov(ebx, FieldOperand(esi, kGlobalOffset)); 609 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); 610 611 // Push the receiver. 612 __ bind(&push_receiver); 613 __ push(ebx); 614 615 // Copy all arguments from the array to the stack. 616 Label entry, loop; 617 __ mov(eax, Operand(ebp, kIndexOffset)); 618 __ jmp(&entry); 619 __ bind(&loop); 620 __ mov(ecx, Operand(ebp, 2 * kPointerSize)); // load arguments 621 __ push(ecx); 622 __ push(eax); 623 624 // Use inline caching to speed up access to arguments. 625 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 626 __ call(ic, RelocInfo::CODE_TARGET); 627 // It is important that we do not have a test instruction after the 628 // call. A test instruction after the call is used to indicate that 629 // we have generated an inline version of the keyed load. In this 630 // case, we know that we are not generating a test instruction next. 631 632 // Remove IC arguments from the stack and push the nth argument. 633 __ add(Operand(esp), Immediate(2 * kPointerSize)); 634 __ push(eax); 635 636 // Update the index on the stack and in register eax. 637 __ mov(eax, Operand(ebp, kIndexOffset)); 638 __ add(Operand(eax), Immediate(1 << kSmiTagSize)); 639 __ mov(Operand(ebp, kIndexOffset), eax); 640 641 __ bind(&entry); 642 __ cmp(eax, Operand(ebp, kLimitOffset)); 643 __ j(not_equal, &loop); 644 645 // Invoke the function. 646 ParameterCount actual(eax); 647 __ shr(eax, kSmiTagSize); 648 __ mov(edi, Operand(ebp, 4 * kPointerSize)); 649 __ InvokeFunction(edi, actual, CALL_FUNCTION); 650 651 __ LeaveInternalFrame(); 652 __ ret(3 * kPointerSize); // remove this, receiver, and arguments 653} 654 655 656// Load the built-in Array function from the current context. 657static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) { 658 // Load the global context. 659 __ mov(result, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 660 __ mov(result, FieldOperand(result, GlobalObject::kGlobalContextOffset)); 661 // Load the Array function from the global context. 662 __ mov(result, 663 Operand(result, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); 664} 665 666 667// Number of empty elements to allocate for an empty array. 668static const int kPreallocatedArrayElements = 4; 669 670 671// Allocate an empty JSArray. The allocated array is put into the result 672// register. If the parameter initial_capacity is larger than zero an elements 673// backing store is allocated with this size and filled with the hole values. 674// Otherwise the elements backing store is set to the empty FixedArray. 675static void AllocateEmptyJSArray(MacroAssembler* masm, 676 Register array_function, 677 Register result, 678 Register scratch1, 679 Register scratch2, 680 Register scratch3, 681 int initial_capacity, 682 Label* gc_required) { 683 ASSERT(initial_capacity >= 0); 684 685 // Load the initial map from the array function. 686 __ mov(scratch1, FieldOperand(array_function, 687 JSFunction::kPrototypeOrInitialMapOffset)); 688 689 // Allocate the JSArray object together with space for a fixed array with the 690 // requested elements. 691 int size = JSArray::kSize; 692 if (initial_capacity > 0) { 693 size += FixedArray::SizeFor(initial_capacity); 694 } 695 __ AllocateInNewSpace(size, 696 result, 697 scratch2, 698 scratch3, 699 gc_required, 700 TAG_OBJECT); 701 702 // Allocated the JSArray. Now initialize the fields except for the elements 703 // array. 704 // result: JSObject 705 // scratch1: initial map 706 // scratch2: start of next object 707 __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1); 708 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), 709 Factory::empty_fixed_array()); 710 // Field JSArray::kElementsOffset is initialized later. 711 __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0)); 712 713 // If no storage is requested for the elements array just set the empty 714 // fixed array. 715 if (initial_capacity == 0) { 716 __ mov(FieldOperand(result, JSArray::kElementsOffset), 717 Factory::empty_fixed_array()); 718 return; 719 } 720 721 // Calculate the location of the elements array and set elements array member 722 // of the JSArray. 723 // result: JSObject 724 // scratch2: start of next object 725 __ lea(scratch1, Operand(result, JSArray::kSize)); 726 __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1); 727 728 // Initialize the FixedArray and fill it with holes. FixedArray length is not 729 // stored as a smi. 730 // result: JSObject 731 // scratch1: elements array 732 // scratch2: start of next object 733 __ mov(FieldOperand(scratch1, JSObject::kMapOffset), 734 Factory::fixed_array_map()); 735 __ mov(FieldOperand(scratch1, Array::kLengthOffset), 736 Immediate(initial_capacity)); 737 738 // Fill the FixedArray with the hole value. Inline the code if short. 739 // Reconsider loop unfolding if kPreallocatedArrayElements gets changed. 740 static const int kLoopUnfoldLimit = 4; 741 ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit); 742 if (initial_capacity <= kLoopUnfoldLimit) { 743 // Use a scratch register here to have only one reloc info when unfolding 744 // the loop. 745 __ mov(scratch3, Factory::the_hole_value()); 746 for (int i = 0; i < initial_capacity; i++) { 747 __ mov(FieldOperand(scratch1, 748 FixedArray::kHeaderSize + i * kPointerSize), 749 scratch3); 750 } 751 } else { 752 Label loop, entry; 753 __ jmp(&entry); 754 __ bind(&loop); 755 __ mov(Operand(scratch1, 0), Factory::the_hole_value()); 756 __ add(Operand(scratch1), Immediate(kPointerSize)); 757 __ bind(&entry); 758 __ cmp(scratch1, Operand(scratch2)); 759 __ j(below, &loop); 760 } 761} 762 763 764// Allocate a JSArray with the number of elements stored in a register. The 765// register array_function holds the built-in Array function and the register 766// array_size holds the size of the array as a smi. The allocated array is put 767// into the result register and beginning and end of the FixedArray elements 768// storage is put into registers elements_array and elements_array_end (see 769// below for when that is not the case). If the parameter fill_with_holes is 770// true the allocated elements backing store is filled with the hole values 771// otherwise it is left uninitialized. When the backing store is filled the 772// register elements_array is scratched. 773static void AllocateJSArray(MacroAssembler* masm, 774 Register array_function, // Array function. 775 Register array_size, // As a smi. 776 Register result, 777 Register elements_array, 778 Register elements_array_end, 779 Register scratch, 780 bool fill_with_hole, 781 Label* gc_required) { 782 Label not_empty, allocated; 783 784 // Load the initial map from the array function. 785 __ mov(elements_array, 786 FieldOperand(array_function, 787 JSFunction::kPrototypeOrInitialMapOffset)); 788 789 // Check whether an empty sized array is requested. 790 __ test(array_size, Operand(array_size)); 791 __ j(not_zero, ¬_empty); 792 793 // If an empty array is requested allocate a small elements array anyway. This 794 // keeps the code below free of special casing for the empty array. 795 int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements); 796 __ AllocateInNewSpace(size, 797 result, 798 elements_array_end, 799 scratch, 800 gc_required, 801 TAG_OBJECT); 802 __ jmp(&allocated); 803 804 // Allocate the JSArray object together with space for a FixedArray with the 805 // requested elements. 806 __ bind(¬_empty); 807 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 808 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize, 809 times_half_pointer_size, // array_size is a smi. 810 array_size, 811 result, 812 elements_array_end, 813 scratch, 814 gc_required, 815 TAG_OBJECT); 816 817 // Allocated the JSArray. Now initialize the fields except for the elements 818 // array. 819 // result: JSObject 820 // elements_array: initial map 821 // elements_array_end: start of next object 822 // array_size: size of array (smi) 823 __ bind(&allocated); 824 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array); 825 __ mov(elements_array, Factory::empty_fixed_array()); 826 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array); 827 // Field JSArray::kElementsOffset is initialized later. 828 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size); 829 830 // Calculate the location of the elements array and set elements array member 831 // of the JSArray. 832 // result: JSObject 833 // elements_array_end: start of next object 834 // array_size: size of array (smi) 835 __ lea(elements_array, Operand(result, JSArray::kSize)); 836 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array); 837 838 // Initialize the fixed array. FixedArray length is not stored as a smi. 839 // result: JSObject 840 // elements_array: elements array 841 // elements_array_end: start of next object 842 // array_size: size of array (smi) 843 ASSERT(kSmiTag == 0); 844 __ shr(array_size, kSmiTagSize); // Convert from smi to value. 845 __ mov(FieldOperand(elements_array, JSObject::kMapOffset), 846 Factory::fixed_array_map()); 847 Label not_empty_2, fill_array; 848 __ test(array_size, Operand(array_size)); 849 __ j(not_zero, ¬_empty_2); 850 // Length of the FixedArray is the number of pre-allocated elements even 851 // though the actual JSArray has length 0. 852 __ mov(FieldOperand(elements_array, Array::kLengthOffset), 853 Immediate(kPreallocatedArrayElements)); 854 __ jmp(&fill_array); 855 __ bind(¬_empty_2); 856 // For non-empty JSArrays the length of the FixedArray and the JSArray is the 857 // same. 858 __ mov(FieldOperand(elements_array, Array::kLengthOffset), array_size); 859 860 // Fill the allocated FixedArray with the hole value if requested. 861 // result: JSObject 862 // elements_array: elements array 863 // elements_array_end: start of next object 864 __ bind(&fill_array); 865 if (fill_with_hole) { 866 Label loop, entry; 867 __ mov(scratch, Factory::the_hole_value()); 868 __ lea(elements_array, Operand(elements_array, 869 FixedArray::kHeaderSize - kHeapObjectTag)); 870 __ jmp(&entry); 871 __ bind(&loop); 872 __ mov(Operand(elements_array, 0), scratch); 873 __ add(Operand(elements_array), Immediate(kPointerSize)); 874 __ bind(&entry); 875 __ cmp(elements_array, Operand(elements_array_end)); 876 __ j(below, &loop); 877 } 878} 879 880 881// Create a new array for the built-in Array function. This function allocates 882// the JSArray object and the FixedArray elements array and initializes these. 883// If the Array cannot be constructed in native code the runtime is called. This 884// function assumes the following state: 885// edi: constructor (built-in Array function) 886// eax: argc 887// esp[0]: return address 888// esp[4]: last argument 889// This function is used for both construct and normal calls of Array. Whether 890// it is a construct call or not is indicated by the construct_call parameter. 891// The only difference between handling a construct call and a normal call is 892// that for a construct call the constructor function in edi needs to be 893// preserved for entering the generic code. In both cases argc in eax needs to 894// be preserved. 895static void ArrayNativeCode(MacroAssembler* masm, 896 bool construct_call, 897 Label *call_generic_code) { 898 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call; 899 900 // Push the constructor and argc. No need to tag argc as a smi, as there will 901 // be no garbage collection with this on the stack. 902 int push_count = 0; 903 if (construct_call) { 904 push_count++; 905 __ push(edi); 906 } 907 push_count++; 908 __ push(eax); 909 910 // Check for array construction with zero arguments. 911 __ test(eax, Operand(eax)); 912 __ j(not_zero, &argc_one_or_more); 913 914 // Handle construction of an empty array. 915 AllocateEmptyJSArray(masm, 916 edi, 917 eax, 918 ebx, 919 ecx, 920 edi, 921 kPreallocatedArrayElements, 922 &prepare_generic_code_call); 923 __ IncrementCounter(&Counters::array_function_native, 1); 924 __ pop(ebx); 925 if (construct_call) { 926 __ pop(edi); 927 } 928 __ ret(kPointerSize); 929 930 // Check for one argument. Bail out if argument is not smi or if it is 931 // negative. 932 __ bind(&argc_one_or_more); 933 __ cmp(eax, 1); 934 __ j(not_equal, &argc_two_or_more); 935 ASSERT(kSmiTag == 0); 936 __ test(Operand(esp, (push_count + 1) * kPointerSize), 937 Immediate(kIntptrSignBit | kSmiTagMask)); 938 __ j(not_zero, &prepare_generic_code_call); 939 940 // Handle construction of an empty array of a certain size. Get the size from 941 // the stack and bail out if size is to large to actually allocate an elements 942 // array. 943 __ mov(edx, Operand(esp, (push_count + 1) * kPointerSize)); 944 ASSERT(kSmiTag == 0); 945 __ cmp(edx, JSObject::kInitialMaxFastElementArray << kSmiTagSize); 946 __ j(greater_equal, &prepare_generic_code_call); 947 948 // edx: array_size (smi) 949 // edi: constructor 950 // esp[0]: argc 951 // esp[4]: constructor (only if construct_call) 952 // esp[8]: return address 953 // esp[C]: argument 954 AllocateJSArray(masm, 955 edi, 956 edx, 957 eax, 958 ebx, 959 ecx, 960 edi, 961 true, 962 &prepare_generic_code_call); 963 __ IncrementCounter(&Counters::array_function_native, 1); 964 __ pop(ebx); 965 if (construct_call) { 966 __ pop(edi); 967 } 968 __ ret(2 * kPointerSize); 969 970 // Handle construction of an array from a list of arguments. 971 __ bind(&argc_two_or_more); 972 ASSERT(kSmiTag == 0); 973 __ shl(eax, kSmiTagSize); // Convet argc to a smi. 974 // eax: array_size (smi) 975 // edi: constructor 976 // esp[0] : argc 977 // esp[4]: constructor (only if construct_call) 978 // esp[8] : return address 979 // esp[C] : last argument 980 AllocateJSArray(masm, 981 edi, 982 eax, 983 ebx, 984 ecx, 985 edx, 986 edi, 987 false, 988 &prepare_generic_code_call); 989 __ IncrementCounter(&Counters::array_function_native, 1); 990 __ mov(eax, ebx); 991 __ pop(ebx); 992 if (construct_call) { 993 __ pop(edi); 994 } 995 __ push(eax); 996 // eax: JSArray 997 // ebx: argc 998 // edx: elements_array_end (untagged) 999 // esp[0]: JSArray 1000 // esp[4]: return address 1001 // esp[8]: last argument 1002 1003 // Location of the last argument 1004 __ lea(edi, Operand(esp, 2 * kPointerSize)); 1005 1006 // Location of the first array element (Parameter fill_with_holes to 1007 // AllocateJSArrayis false, so the FixedArray is returned in ecx). 1008 __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag)); 1009 1010 // ebx: argc 1011 // edx: location of the first array element 1012 // edi: location of the last argument 1013 // esp[0]: JSArray 1014 // esp[4]: return address 1015 // esp[8]: last argument 1016 Label loop, entry; 1017 __ mov(ecx, ebx); 1018 __ jmp(&entry); 1019 __ bind(&loop); 1020 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0)); 1021 __ mov(Operand(edx, 0), eax); 1022 __ add(Operand(edx), Immediate(kPointerSize)); 1023 __ bind(&entry); 1024 __ dec(ecx); 1025 __ j(greater_equal, &loop); 1026 1027 // Remove caller arguments from the stack and return. 1028 // ebx: argc 1029 // esp[0]: JSArray 1030 // esp[4]: return address 1031 // esp[8]: last argument 1032 __ pop(eax); 1033 __ pop(ecx); 1034 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize)); 1035 __ push(ecx); 1036 __ ret(0); 1037 1038 // Restore argc and constructor before running the generic code. 1039 __ bind(&prepare_generic_code_call); 1040 __ pop(eax); 1041 if (construct_call) { 1042 __ pop(edi); 1043 } 1044 __ jmp(call_generic_code); 1045} 1046 1047 1048void Builtins::Generate_ArrayCode(MacroAssembler* masm) { 1049 // ----------- S t a t e ------------- 1050 // -- eax : argc 1051 // -- esp[0] : return address 1052 // -- esp[4] : last argument 1053 // ----------------------------------- 1054 Label generic_array_code, one_or_more_arguments, two_or_more_arguments; 1055 1056 // Get the Array function. 1057 GenerateLoadArrayFunction(masm, edi); 1058 1059 if (FLAG_debug_code) { 1060 // Initial map for the builtin Array function shoud be a map. 1061 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 1062 // Will both indicate a NULL and a Smi. 1063 __ test(ebx, Immediate(kSmiTagMask)); 1064 __ Assert(not_zero, "Unexpected initial map for Array function"); 1065 __ CmpObjectType(ebx, MAP_TYPE, ecx); 1066 __ Assert(equal, "Unexpected initial map for Array function"); 1067 } 1068 1069 // Run the native code for the Array function called as a normal function. 1070 ArrayNativeCode(masm, false, &generic_array_code); 1071 1072 // Jump to the generic array code in case the specialized code cannot handle 1073 // the construction. 1074 __ bind(&generic_array_code); 1075 Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric); 1076 Handle<Code> array_code(code); 1077 __ jmp(array_code, RelocInfo::CODE_TARGET); 1078} 1079 1080 1081void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) { 1082 // ----------- S t a t e ------------- 1083 // -- eax : argc 1084 // -- edi : constructor 1085 // -- esp[0] : return address 1086 // -- esp[4] : last argument 1087 // ----------------------------------- 1088 Label generic_constructor; 1089 1090 if (FLAG_debug_code) { 1091 // The array construct code is only set for the builtin Array function which 1092 // does always have a map. 1093 GenerateLoadArrayFunction(masm, ebx); 1094 __ cmp(edi, Operand(ebx)); 1095 __ Assert(equal, "Unexpected Array function"); 1096 // Initial map for the builtin Array function should be a map. 1097 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 1098 // Will both indicate a NULL and a Smi. 1099 __ test(ebx, Immediate(kSmiTagMask)); 1100 __ Assert(not_zero, "Unexpected initial map for Array function"); 1101 __ CmpObjectType(ebx, MAP_TYPE, ecx); 1102 __ Assert(equal, "Unexpected initial map for Array function"); 1103 } 1104 1105 // Run the native code for the Array function called as constructor. 1106 ArrayNativeCode(masm, true, &generic_constructor); 1107 1108 // Jump to the generic construct code in case the specialized code cannot 1109 // handle the construction. 1110 __ bind(&generic_constructor); 1111 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); 1112 Handle<Code> generic_construct_stub(code); 1113 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); 1114} 1115 1116 1117static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { 1118 __ push(ebp); 1119 __ mov(ebp, Operand(esp)); 1120 1121 // Store the arguments adaptor context sentinel. 1122 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 1123 1124 // Push the function on the stack. 1125 __ push(edi); 1126 1127 // Preserve the number of arguments on the stack. Must preserve both 1128 // eax and ebx because these registers are used when copying the 1129 // arguments and the receiver. 1130 ASSERT(kSmiTagSize == 1); 1131 __ lea(ecx, Operand(eax, eax, times_1, kSmiTag)); 1132 __ push(ecx); 1133} 1134 1135 1136static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { 1137 // Retrieve the number of arguments from the stack. 1138 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset)); 1139 1140 // Leave the frame. 1141 __ leave(); 1142 1143 // Remove caller arguments from the stack. 1144 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 1145 __ pop(ecx); 1146 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver 1147 __ push(ecx); 1148} 1149 1150 1151void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { 1152 // ----------- S t a t e ------------- 1153 // -- eax : actual number of arguments 1154 // -- ebx : expected number of arguments 1155 // -- edx : code entry to call 1156 // ----------------------------------- 1157 1158 Label invoke, dont_adapt_arguments; 1159 __ IncrementCounter(&Counters::arguments_adaptors, 1); 1160 1161 Label enough, too_few; 1162 __ cmp(eax, Operand(ebx)); 1163 __ j(less, &too_few); 1164 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); 1165 __ j(equal, &dont_adapt_arguments); 1166 1167 { // Enough parameters: Actual >= expected. 1168 __ bind(&enough); 1169 EnterArgumentsAdaptorFrame(masm); 1170 1171 // Copy receiver and all expected arguments. 1172 const int offset = StandardFrameConstants::kCallerSPOffset; 1173 __ lea(eax, Operand(ebp, eax, times_4, offset)); 1174 __ mov(ecx, -1); // account for receiver 1175 1176 Label copy; 1177 __ bind(©); 1178 __ inc(ecx); 1179 __ push(Operand(eax, 0)); 1180 __ sub(Operand(eax), Immediate(kPointerSize)); 1181 __ cmp(ecx, Operand(ebx)); 1182 __ j(less, ©); 1183 __ jmp(&invoke); 1184 } 1185 1186 { // Too few parameters: Actual < expected. 1187 __ bind(&too_few); 1188 EnterArgumentsAdaptorFrame(masm); 1189 1190 // Copy receiver and all actual arguments. 1191 const int offset = StandardFrameConstants::kCallerSPOffset; 1192 __ lea(edi, Operand(ebp, eax, times_4, offset)); 1193 __ mov(ecx, -1); // account for receiver 1194 1195 Label copy; 1196 __ bind(©); 1197 __ inc(ecx); 1198 __ push(Operand(edi, 0)); 1199 __ sub(Operand(edi), Immediate(kPointerSize)); 1200 __ cmp(ecx, Operand(eax)); 1201 __ j(less, ©); 1202 1203 // Fill remaining expected arguments with undefined values. 1204 Label fill; 1205 __ bind(&fill); 1206 __ inc(ecx); 1207 __ push(Immediate(Factory::undefined_value())); 1208 __ cmp(ecx, Operand(ebx)); 1209 __ j(less, &fill); 1210 1211 // Restore function pointer. 1212 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 1213 } 1214 1215 // Call the entry point. 1216 __ bind(&invoke); 1217 __ call(Operand(edx)); 1218 1219 // Leave frame and return. 1220 LeaveArgumentsAdaptorFrame(masm); 1221 __ ret(0); 1222 1223 // ------------------------------------------- 1224 // Dont adapt arguments. 1225 // ------------------------------------------- 1226 __ bind(&dont_adapt_arguments); 1227 __ jmp(Operand(edx)); 1228} 1229 1230 1231#undef __ 1232 1233} } // namespace v8::internal 1234