builtins-ia32.cc revision d0582a6c46733687d045e4188a1bcd0123c758a1
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::kGlobalContextOffset)); 466 __ mov(ebx, FieldOperand(ebx, kGlobalIndex)); 467 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); 468 469 __ bind(&patch_receiver); 470 __ mov(Operand(esp, eax, times_4, 0), ebx); 471 472 __ bind(&done); 473 } 474 475 // 4. Shift stuff one slot down the stack. 476 { Label loop; 477 __ lea(ecx, Operand(eax, +1)); // +1 ~ copy receiver too 478 __ bind(&loop); 479 __ mov(ebx, Operand(esp, ecx, times_4, 0)); 480 __ mov(Operand(esp, ecx, times_4, kPointerSize), ebx); 481 __ dec(ecx); 482 __ j(not_zero, &loop); 483 } 484 485 // 5. Remove TOS (copy of last arguments), but keep return address. 486 __ pop(ebx); 487 __ pop(ecx); 488 __ push(ebx); 489 __ dec(eax); 490 491 // 6. Check that function really was a function and get the code to 492 // call from the function and check that the number of expected 493 // arguments matches what we're providing. 494 { Label invoke; 495 __ test(edi, Operand(edi)); 496 __ j(not_zero, &invoke, taken); 497 __ xor_(ebx, Operand(ebx)); 498 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); 499 __ jmp(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 500 RelocInfo::CODE_TARGET); 501 502 __ bind(&invoke); 503 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 504 __ mov(ebx, 505 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); 506 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); 507 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); 508 __ cmp(eax, Operand(ebx)); 509 __ j(not_equal, Handle<Code>(builtin(ArgumentsAdaptorTrampoline))); 510 } 511 512 // 7. Jump (tail-call) to the code in register edx without checking arguments. 513 ParameterCount expected(0); 514 __ InvokeCode(Operand(edx), expected, expected, JUMP_FUNCTION); 515} 516 517 518void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 519 __ EnterInternalFrame(); 520 521 __ push(Operand(ebp, 4 * kPointerSize)); // push this 522 __ push(Operand(ebp, 2 * kPointerSize)); // push arguments 523 __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION); 524 525 // Check the stack for overflow. We are not trying need to catch 526 // interruptions (e.g. debug break and preemption) here, so the "real stack 527 // limit" is checked. 528 Label okay; 529 ExternalReference real_stack_limit = 530 ExternalReference::address_of_real_stack_limit(); 531 __ mov(edi, Operand::StaticVariable(real_stack_limit)); 532 // Make ecx the space we have left. The stack might already be overflowed 533 // here which will cause ecx to become negative. 534 __ mov(ecx, Operand(esp)); 535 __ sub(ecx, Operand(edi)); 536 // Make edx the space we need for the array when it is unrolled onto the 537 // stack. 538 __ mov(edx, Operand(eax)); 539 __ shl(edx, kPointerSizeLog2 - kSmiTagSize); 540 // Check if the arguments will overflow the stack. 541 __ cmp(ecx, Operand(edx)); 542 __ j(greater, &okay, taken); // Signed comparison. 543 544 // Out of stack space. 545 __ push(Operand(ebp, 4 * kPointerSize)); // push this 546 __ push(eax); 547 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); 548 __ bind(&okay); 549 // End of stack check. 550 551 // Push current index and limit. 552 const int kLimitOffset = 553 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; 554 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; 555 __ push(eax); // limit 556 __ push(Immediate(0)); // index 557 558 // Change context eagerly to get the right global object if 559 // necessary. 560 __ mov(edi, Operand(ebp, 4 * kPointerSize)); 561 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 562 563 // Compute the receiver. 564 Label call_to_object, use_global_receiver, push_receiver; 565 __ mov(ebx, Operand(ebp, 3 * kPointerSize)); 566 __ test(ebx, Immediate(kSmiTagMask)); 567 __ j(zero, &call_to_object); 568 __ cmp(ebx, Factory::null_value()); 569 __ j(equal, &use_global_receiver); 570 __ cmp(ebx, Factory::undefined_value()); 571 __ j(equal, &use_global_receiver); 572 573 // If given receiver is already a JavaScript object then there's no 574 // reason for converting it. 575 __ mov(ecx, FieldOperand(ebx, HeapObject::kMapOffset)); 576 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 577 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); 578 __ j(less, &call_to_object); 579 __ cmp(ecx, LAST_JS_OBJECT_TYPE); 580 __ j(less_equal, &push_receiver); 581 582 // Convert the receiver to an object. 583 __ bind(&call_to_object); 584 __ push(ebx); 585 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 586 __ mov(ebx, Operand(eax)); 587 __ jmp(&push_receiver); 588 589 // Use the current global receiver object as the receiver. 590 __ bind(&use_global_receiver); 591 const int kGlobalOffset = 592 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 593 __ mov(ebx, FieldOperand(esi, kGlobalOffset)); 594 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalContextOffset)); 595 __ mov(ebx, FieldOperand(ebx, kGlobalOffset)); 596 __ mov(ebx, FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset)); 597 598 // Push the receiver. 599 __ bind(&push_receiver); 600 __ push(ebx); 601 602 // Copy all arguments from the array to the stack. 603 Label entry, loop; 604 __ mov(eax, Operand(ebp, kIndexOffset)); 605 __ jmp(&entry); 606 __ bind(&loop); 607 __ mov(ecx, Operand(ebp, 2 * kPointerSize)); // load arguments 608 __ push(ecx); 609 __ push(eax); 610 611 // Use inline caching to speed up access to arguments. 612 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 613 __ call(ic, RelocInfo::CODE_TARGET); 614 // It is important that we do not have a test instruction after the 615 // call. A test instruction after the call is used to indicate that 616 // we have generated an inline version of the keyed load. In this 617 // case, we know that we are not generating a test instruction next. 618 619 // Remove IC arguments from the stack and push the nth argument. 620 __ add(Operand(esp), Immediate(2 * kPointerSize)); 621 __ push(eax); 622 623 // Update the index on the stack and in register eax. 624 __ mov(eax, Operand(ebp, kIndexOffset)); 625 __ add(Operand(eax), Immediate(1 << kSmiTagSize)); 626 __ mov(Operand(ebp, kIndexOffset), eax); 627 628 __ bind(&entry); 629 __ cmp(eax, Operand(ebp, kLimitOffset)); 630 __ j(not_equal, &loop); 631 632 // Invoke the function. 633 ParameterCount actual(eax); 634 __ shr(eax, kSmiTagSize); 635 __ mov(edi, Operand(ebp, 4 * kPointerSize)); 636 __ InvokeFunction(edi, actual, CALL_FUNCTION); 637 638 __ LeaveInternalFrame(); 639 __ ret(3 * kPointerSize); // remove this, receiver, and arguments 640} 641 642 643// Load the built-in Array function from the current context. 644static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) { 645 // Load the global context. 646 __ mov(result, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 647 __ mov(result, FieldOperand(result, GlobalObject::kGlobalContextOffset)); 648 // Load the Array function from the global context. 649 __ mov(result, 650 Operand(result, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX))); 651} 652 653 654// Number of empty elements to allocate for an empty array. 655static const int kPreallocatedArrayElements = 4; 656 657 658// Allocate an empty JSArray. The allocated array is put into the result 659// register. If the parameter initial_capacity is larger than zero an elements 660// backing store is allocated with this size and filled with the hole values. 661// Otherwise the elements backing store is set to the empty FixedArray. 662static void AllocateEmptyJSArray(MacroAssembler* masm, 663 Register array_function, 664 Register result, 665 Register scratch1, 666 Register scratch2, 667 Register scratch3, 668 int initial_capacity, 669 Label* gc_required) { 670 ASSERT(initial_capacity >= 0); 671 672 // Load the initial map from the array function. 673 __ mov(scratch1, FieldOperand(array_function, 674 JSFunction::kPrototypeOrInitialMapOffset)); 675 676 // Allocate the JSArray object together with space for a fixed array with the 677 // requested elements. 678 int size = JSArray::kSize; 679 if (initial_capacity > 0) { 680 size += FixedArray::SizeFor(initial_capacity); 681 } 682 __ AllocateInNewSpace(size, 683 result, 684 scratch2, 685 scratch3, 686 gc_required, 687 TAG_OBJECT); 688 689 // Allocated the JSArray. Now initialize the fields except for the elements 690 // array. 691 // result: JSObject 692 // scratch1: initial map 693 // scratch2: start of next object 694 __ mov(FieldOperand(result, JSObject::kMapOffset), scratch1); 695 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), 696 Factory::empty_fixed_array()); 697 // Field JSArray::kElementsOffset is initialized later. 698 __ mov(FieldOperand(result, JSArray::kLengthOffset), Immediate(0)); 699 700 // If no storage is requested for the elements array just set the empty 701 // fixed array. 702 if (initial_capacity == 0) { 703 __ mov(FieldOperand(result, JSArray::kElementsOffset), 704 Factory::empty_fixed_array()); 705 return; 706 } 707 708 // Calculate the location of the elements array and set elements array member 709 // of the JSArray. 710 // result: JSObject 711 // scratch2: start of next object 712 __ lea(scratch1, Operand(result, JSArray::kSize)); 713 __ mov(FieldOperand(result, JSArray::kElementsOffset), scratch1); 714 715 // Initialize the FixedArray and fill it with holes. FixedArray length is not 716 // stored as a smi. 717 // result: JSObject 718 // scratch1: elements array 719 // scratch2: start of next object 720 __ mov(FieldOperand(scratch1, JSObject::kMapOffset), 721 Factory::fixed_array_map()); 722 __ mov(FieldOperand(scratch1, Array::kLengthOffset), 723 Immediate(initial_capacity)); 724 725 // Fill the FixedArray with the hole value. Inline the code if short. 726 // Reconsider loop unfolding if kPreallocatedArrayElements gets changed. 727 static const int kLoopUnfoldLimit = 4; 728 ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit); 729 if (initial_capacity <= kLoopUnfoldLimit) { 730 // Use a scratch register here to have only one reloc info when unfolding 731 // the loop. 732 __ mov(scratch3, Factory::the_hole_value()); 733 for (int i = 0; i < initial_capacity; i++) { 734 __ mov(FieldOperand(scratch1, 735 FixedArray::kHeaderSize + i * kPointerSize), 736 scratch3); 737 } 738 } else { 739 Label loop, entry; 740 __ jmp(&entry); 741 __ bind(&loop); 742 __ mov(Operand(scratch1, 0), Factory::the_hole_value()); 743 __ add(Operand(scratch1), Immediate(kPointerSize)); 744 __ bind(&entry); 745 __ cmp(scratch1, Operand(scratch2)); 746 __ j(below, &loop); 747 } 748} 749 750 751// Allocate a JSArray with the number of elements stored in a register. The 752// register array_function holds the built-in Array function and the register 753// array_size holds the size of the array as a smi. The allocated array is put 754// into the result register and beginning and end of the FixedArray elements 755// storage is put into registers elements_array and elements_array_end (see 756// below for when that is not the case). If the parameter fill_with_holes is 757// true the allocated elements backing store is filled with the hole values 758// otherwise it is left uninitialized. When the backing store is filled the 759// register elements_array is scratched. 760static void AllocateJSArray(MacroAssembler* masm, 761 Register array_function, // Array function. 762 Register array_size, // As a smi. 763 Register result, 764 Register elements_array, 765 Register elements_array_end, 766 Register scratch, 767 bool fill_with_hole, 768 Label* gc_required) { 769 Label not_empty, allocated; 770 771 // Load the initial map from the array function. 772 __ mov(elements_array, 773 FieldOperand(array_function, 774 JSFunction::kPrototypeOrInitialMapOffset)); 775 776 // Check whether an empty sized array is requested. 777 __ test(array_size, Operand(array_size)); 778 __ j(not_zero, ¬_empty); 779 780 // If an empty array is requested allocate a small elements array anyway. This 781 // keeps the code below free of special casing for the empty array. 782 int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements); 783 __ AllocateInNewSpace(size, 784 result, 785 elements_array_end, 786 scratch, 787 gc_required, 788 TAG_OBJECT); 789 __ jmp(&allocated); 790 791 // Allocate the JSArray object together with space for a FixedArray with the 792 // requested elements. 793 __ bind(¬_empty); 794 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 795 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize, 796 times_half_pointer_size, // array_size is a smi. 797 array_size, 798 result, 799 elements_array_end, 800 scratch, 801 gc_required, 802 TAG_OBJECT); 803 804 // Allocated the JSArray. Now initialize the fields except for the elements 805 // array. 806 // result: JSObject 807 // elements_array: initial map 808 // elements_array_end: start of next object 809 // array_size: size of array (smi) 810 __ bind(&allocated); 811 __ mov(FieldOperand(result, JSObject::kMapOffset), elements_array); 812 __ mov(elements_array, Factory::empty_fixed_array()); 813 __ mov(FieldOperand(result, JSArray::kPropertiesOffset), elements_array); 814 // Field JSArray::kElementsOffset is initialized later. 815 __ mov(FieldOperand(result, JSArray::kLengthOffset), array_size); 816 817 // Calculate the location of the elements array and set elements array member 818 // of the JSArray. 819 // result: JSObject 820 // elements_array_end: start of next object 821 // array_size: size of array (smi) 822 __ lea(elements_array, Operand(result, JSArray::kSize)); 823 __ mov(FieldOperand(result, JSArray::kElementsOffset), elements_array); 824 825 // Initialize the fixed array. FixedArray length is not stored as a smi. 826 // result: JSObject 827 // elements_array: elements array 828 // elements_array_end: start of next object 829 // array_size: size of array (smi) 830 ASSERT(kSmiTag == 0); 831 __ shr(array_size, kSmiTagSize); // Convert from smi to value. 832 __ mov(FieldOperand(elements_array, JSObject::kMapOffset), 833 Factory::fixed_array_map()); 834 Label not_empty_2, fill_array; 835 __ test(array_size, Operand(array_size)); 836 __ j(not_zero, ¬_empty_2); 837 // Length of the FixedArray is the number of pre-allocated elements even 838 // though the actual JSArray has length 0. 839 __ mov(FieldOperand(elements_array, Array::kLengthOffset), 840 Immediate(kPreallocatedArrayElements)); 841 __ jmp(&fill_array); 842 __ bind(¬_empty_2); 843 // For non-empty JSArrays the length of the FixedArray and the JSArray is the 844 // same. 845 __ mov(FieldOperand(elements_array, Array::kLengthOffset), array_size); 846 847 // Fill the allocated FixedArray with the hole value if requested. 848 // result: JSObject 849 // elements_array: elements array 850 // elements_array_end: start of next object 851 __ bind(&fill_array); 852 if (fill_with_hole) { 853 Label loop, entry; 854 __ mov(scratch, Factory::the_hole_value()); 855 __ lea(elements_array, Operand(elements_array, 856 FixedArray::kHeaderSize - kHeapObjectTag)); 857 __ jmp(&entry); 858 __ bind(&loop); 859 __ mov(Operand(elements_array, 0), scratch); 860 __ add(Operand(elements_array), Immediate(kPointerSize)); 861 __ bind(&entry); 862 __ cmp(elements_array, Operand(elements_array_end)); 863 __ j(below, &loop); 864 } 865} 866 867 868// Create a new array for the built-in Array function. This function allocates 869// the JSArray object and the FixedArray elements array and initializes these. 870// If the Array cannot be constructed in native code the runtime is called. This 871// function assumes the following state: 872// edi: constructor (built-in Array function) 873// eax: argc 874// esp[0]: return address 875// esp[4]: last argument 876// This function is used for both construct and normal calls of Array. Whether 877// it is a construct call or not is indicated by the construct_call parameter. 878// The only difference between handling a construct call and a normal call is 879// that for a construct call the constructor function in edi needs to be 880// preserved for entering the generic code. In both cases argc in eax needs to 881// be preserved. 882static void ArrayNativeCode(MacroAssembler* masm, 883 bool construct_call, 884 Label* call_generic_code) { 885 Label argc_one_or_more, argc_two_or_more, prepare_generic_code_call; 886 887 // Push the constructor and argc. No need to tag argc as a smi, as there will 888 // be no garbage collection with this on the stack. 889 int push_count = 0; 890 if (construct_call) { 891 push_count++; 892 __ push(edi); 893 } 894 push_count++; 895 __ push(eax); 896 897 // Check for array construction with zero arguments. 898 __ test(eax, Operand(eax)); 899 __ j(not_zero, &argc_one_or_more); 900 901 // Handle construction of an empty array. 902 AllocateEmptyJSArray(masm, 903 edi, 904 eax, 905 ebx, 906 ecx, 907 edi, 908 kPreallocatedArrayElements, 909 &prepare_generic_code_call); 910 __ IncrementCounter(&Counters::array_function_native, 1); 911 __ pop(ebx); 912 if (construct_call) { 913 __ pop(edi); 914 } 915 __ ret(kPointerSize); 916 917 // Check for one argument. Bail out if argument is not smi or if it is 918 // negative. 919 __ bind(&argc_one_or_more); 920 __ cmp(eax, 1); 921 __ j(not_equal, &argc_two_or_more); 922 ASSERT(kSmiTag == 0); 923 __ test(Operand(esp, (push_count + 1) * kPointerSize), 924 Immediate(kIntptrSignBit | kSmiTagMask)); 925 __ j(not_zero, &prepare_generic_code_call); 926 927 // Handle construction of an empty array of a certain size. Get the size from 928 // the stack and bail out if size is to large to actually allocate an elements 929 // array. 930 __ mov(edx, Operand(esp, (push_count + 1) * kPointerSize)); 931 ASSERT(kSmiTag == 0); 932 __ cmp(edx, JSObject::kInitialMaxFastElementArray << kSmiTagSize); 933 __ j(greater_equal, &prepare_generic_code_call); 934 935 // edx: array_size (smi) 936 // edi: constructor 937 // esp[0]: argc 938 // esp[4]: constructor (only if construct_call) 939 // esp[8]: return address 940 // esp[C]: argument 941 AllocateJSArray(masm, 942 edi, 943 edx, 944 eax, 945 ebx, 946 ecx, 947 edi, 948 true, 949 &prepare_generic_code_call); 950 __ IncrementCounter(&Counters::array_function_native, 1); 951 __ pop(ebx); 952 if (construct_call) { 953 __ pop(edi); 954 } 955 __ ret(2 * kPointerSize); 956 957 // Handle construction of an array from a list of arguments. 958 __ bind(&argc_two_or_more); 959 ASSERT(kSmiTag == 0); 960 __ shl(eax, kSmiTagSize); // Convet argc to a smi. 961 // eax: array_size (smi) 962 // edi: constructor 963 // esp[0] : argc 964 // esp[4]: constructor (only if construct_call) 965 // esp[8] : return address 966 // esp[C] : last argument 967 AllocateJSArray(masm, 968 edi, 969 eax, 970 ebx, 971 ecx, 972 edx, 973 edi, 974 false, 975 &prepare_generic_code_call); 976 __ IncrementCounter(&Counters::array_function_native, 1); 977 __ mov(eax, ebx); 978 __ pop(ebx); 979 if (construct_call) { 980 __ pop(edi); 981 } 982 __ push(eax); 983 // eax: JSArray 984 // ebx: argc 985 // edx: elements_array_end (untagged) 986 // esp[0]: JSArray 987 // esp[4]: return address 988 // esp[8]: last argument 989 990 // Location of the last argument 991 __ lea(edi, Operand(esp, 2 * kPointerSize)); 992 993 // Location of the first array element (Parameter fill_with_holes to 994 // AllocateJSArrayis false, so the FixedArray is returned in ecx). 995 __ lea(edx, Operand(ecx, FixedArray::kHeaderSize - kHeapObjectTag)); 996 997 // ebx: argc 998 // edx: location of the first array element 999 // edi: location of the last argument 1000 // esp[0]: JSArray 1001 // esp[4]: return address 1002 // esp[8]: last argument 1003 Label loop, entry; 1004 __ mov(ecx, ebx); 1005 __ jmp(&entry); 1006 __ bind(&loop); 1007 __ mov(eax, Operand(edi, ecx, times_pointer_size, 0)); 1008 __ mov(Operand(edx, 0), eax); 1009 __ add(Operand(edx), Immediate(kPointerSize)); 1010 __ bind(&entry); 1011 __ dec(ecx); 1012 __ j(greater_equal, &loop); 1013 1014 // Remove caller arguments from the stack and return. 1015 // ebx: argc 1016 // esp[0]: JSArray 1017 // esp[4]: return address 1018 // esp[8]: last argument 1019 __ pop(eax); 1020 __ pop(ecx); 1021 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize)); 1022 __ push(ecx); 1023 __ ret(0); 1024 1025 // Restore argc and constructor before running the generic code. 1026 __ bind(&prepare_generic_code_call); 1027 __ pop(eax); 1028 if (construct_call) { 1029 __ pop(edi); 1030 } 1031 __ jmp(call_generic_code); 1032} 1033 1034 1035void Builtins::Generate_ArrayCode(MacroAssembler* masm) { 1036 // ----------- S t a t e ------------- 1037 // -- eax : argc 1038 // -- esp[0] : return address 1039 // -- esp[4] : last argument 1040 // ----------------------------------- 1041 Label generic_array_code, one_or_more_arguments, two_or_more_arguments; 1042 1043 // Get the Array function. 1044 GenerateLoadArrayFunction(masm, edi); 1045 1046 if (FLAG_debug_code) { 1047 // Initial map for the builtin Array function shoud be a map. 1048 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 1049 // Will both indicate a NULL and a Smi. 1050 __ test(ebx, Immediate(kSmiTagMask)); 1051 __ Assert(not_zero, "Unexpected initial map for Array function"); 1052 __ CmpObjectType(ebx, MAP_TYPE, ecx); 1053 __ Assert(equal, "Unexpected initial map for Array function"); 1054 } 1055 1056 // Run the native code for the Array function called as a normal function. 1057 ArrayNativeCode(masm, false, &generic_array_code); 1058 1059 // Jump to the generic array code in case the specialized code cannot handle 1060 // the construction. 1061 __ bind(&generic_array_code); 1062 Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric); 1063 Handle<Code> array_code(code); 1064 __ jmp(array_code, RelocInfo::CODE_TARGET); 1065} 1066 1067 1068void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) { 1069 // ----------- S t a t e ------------- 1070 // -- eax : argc 1071 // -- edi : constructor 1072 // -- esp[0] : return address 1073 // -- esp[4] : last argument 1074 // ----------------------------------- 1075 Label generic_constructor; 1076 1077 if (FLAG_debug_code) { 1078 // The array construct code is only set for the builtin Array function which 1079 // does always have a map. 1080 GenerateLoadArrayFunction(masm, ebx); 1081 __ cmp(edi, Operand(ebx)); 1082 __ Assert(equal, "Unexpected Array function"); 1083 // Initial map for the builtin Array function should be a map. 1084 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 1085 // Will both indicate a NULL and a Smi. 1086 __ test(ebx, Immediate(kSmiTagMask)); 1087 __ Assert(not_zero, "Unexpected initial map for Array function"); 1088 __ CmpObjectType(ebx, MAP_TYPE, ecx); 1089 __ Assert(equal, "Unexpected initial map for Array function"); 1090 } 1091 1092 // Run the native code for the Array function called as constructor. 1093 ArrayNativeCode(masm, true, &generic_constructor); 1094 1095 // Jump to the generic construct code in case the specialized code cannot 1096 // handle the construction. 1097 __ bind(&generic_constructor); 1098 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); 1099 Handle<Code> generic_construct_stub(code); 1100 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); 1101} 1102 1103 1104static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { 1105 __ push(ebp); 1106 __ mov(ebp, Operand(esp)); 1107 1108 // Store the arguments adaptor context sentinel. 1109 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 1110 1111 // Push the function on the stack. 1112 __ push(edi); 1113 1114 // Preserve the number of arguments on the stack. Must preserve both 1115 // eax and ebx because these registers are used when copying the 1116 // arguments and the receiver. 1117 ASSERT(kSmiTagSize == 1); 1118 __ lea(ecx, Operand(eax, eax, times_1, kSmiTag)); 1119 __ push(ecx); 1120} 1121 1122 1123static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { 1124 // Retrieve the number of arguments from the stack. 1125 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset)); 1126 1127 // Leave the frame. 1128 __ leave(); 1129 1130 // Remove caller arguments from the stack. 1131 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 1132 __ pop(ecx); 1133 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver 1134 __ push(ecx); 1135} 1136 1137 1138void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { 1139 // ----------- S t a t e ------------- 1140 // -- eax : actual number of arguments 1141 // -- ebx : expected number of arguments 1142 // -- edx : code entry to call 1143 // ----------------------------------- 1144 1145 Label invoke, dont_adapt_arguments; 1146 __ IncrementCounter(&Counters::arguments_adaptors, 1); 1147 1148 Label enough, too_few; 1149 __ cmp(eax, Operand(ebx)); 1150 __ j(less, &too_few); 1151 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); 1152 __ j(equal, &dont_adapt_arguments); 1153 1154 { // Enough parameters: Actual >= expected. 1155 __ bind(&enough); 1156 EnterArgumentsAdaptorFrame(masm); 1157 1158 // Copy receiver and all expected arguments. 1159 const int offset = StandardFrameConstants::kCallerSPOffset; 1160 __ lea(eax, Operand(ebp, eax, times_4, offset)); 1161 __ mov(ecx, -1); // account for receiver 1162 1163 Label copy; 1164 __ bind(©); 1165 __ inc(ecx); 1166 __ push(Operand(eax, 0)); 1167 __ sub(Operand(eax), Immediate(kPointerSize)); 1168 __ cmp(ecx, Operand(ebx)); 1169 __ j(less, ©); 1170 __ jmp(&invoke); 1171 } 1172 1173 { // Too few parameters: Actual < expected. 1174 __ bind(&too_few); 1175 EnterArgumentsAdaptorFrame(masm); 1176 1177 // Copy receiver and all actual arguments. 1178 const int offset = StandardFrameConstants::kCallerSPOffset; 1179 __ lea(edi, Operand(ebp, eax, times_4, offset)); 1180 __ mov(ecx, -1); // account for receiver 1181 1182 Label copy; 1183 __ bind(©); 1184 __ inc(ecx); 1185 __ push(Operand(edi, 0)); 1186 __ sub(Operand(edi), Immediate(kPointerSize)); 1187 __ cmp(ecx, Operand(eax)); 1188 __ j(less, ©); 1189 1190 // Fill remaining expected arguments with undefined values. 1191 Label fill; 1192 __ bind(&fill); 1193 __ inc(ecx); 1194 __ push(Immediate(Factory::undefined_value())); 1195 __ cmp(ecx, Operand(ebx)); 1196 __ j(less, &fill); 1197 1198 // Restore function pointer. 1199 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 1200 } 1201 1202 // Call the entry point. 1203 __ bind(&invoke); 1204 __ call(Operand(edx)); 1205 1206 // Leave frame and return. 1207 LeaveArgumentsAdaptorFrame(masm); 1208 __ ret(0); 1209 1210 // ------------------------------------------- 1211 // Dont adapt arguments. 1212 // ------------------------------------------- 1213 __ bind(&dont_adapt_arguments); 1214 __ jmp(Operand(edx)); 1215} 1216 1217 1218#undef __ 1219 1220} } // namespace v8::internal 1221