1// Copyright 2012 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#if V8_TARGET_ARCH_IA32 6 7#include "src/code-factory.h" 8#include "src/codegen.h" 9#include "src/deoptimizer.h" 10#include "src/full-codegen/full-codegen.h" 11#include "src/ia32/frames-ia32.h" 12 13namespace v8 { 14namespace internal { 15 16 17#define __ ACCESS_MASM(masm) 18 19 20void Builtins::Generate_Adaptor(MacroAssembler* masm, 21 CFunctionId id, 22 BuiltinExtraArguments extra_args) { 23 // ----------- S t a t e ------------- 24 // -- eax : number of arguments excluding receiver 25 // -- edi : target 26 // -- edx : new.target 27 // -- esp[0] : return address 28 // -- esp[4] : last argument 29 // -- ... 30 // -- esp[4 * argc] : first argument 31 // -- esp[4 * (argc +1)] : receiver 32 // ----------------------------------- 33 __ AssertFunction(edi); 34 35 // Make sure we operate in the context of the called function (for example 36 // ConstructStubs implemented in C++ will be run in the context of the caller 37 // instead of the callee, due to the way that [[Construct]] is defined for 38 // ordinary functions). 39 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 40 41 // Insert extra arguments. 42 int num_extra_args = 0; 43 if (extra_args != BuiltinExtraArguments::kNone) { 44 __ PopReturnAddressTo(ecx); 45 if (extra_args & BuiltinExtraArguments::kTarget) { 46 ++num_extra_args; 47 __ Push(edi); 48 } 49 if (extra_args & BuiltinExtraArguments::kNewTarget) { 50 ++num_extra_args; 51 __ Push(edx); 52 } 53 __ PushReturnAddressFrom(ecx); 54 } 55 56 // JumpToExternalReference expects eax to contain the number of arguments 57 // including the receiver and the extra arguments. 58 __ add(eax, Immediate(num_extra_args + 1)); 59 60 __ JumpToExternalReference(ExternalReference(id, masm->isolate())); 61} 62 63 64static void CallRuntimePassFunction( 65 MacroAssembler* masm, Runtime::FunctionId function_id) { 66 // ----------- S t a t e ------------- 67 // -- edx : new target (preserved for callee) 68 // -- edi : target function (preserved for callee) 69 // ----------------------------------- 70 71 FrameScope scope(masm, StackFrame::INTERNAL); 72 // Push a copy of the target function and the new target. 73 __ push(edi); 74 __ push(edx); 75 // Function is also the parameter to the runtime call. 76 __ push(edi); 77 78 __ CallRuntime(function_id, 1); 79 // Restore target function and new target. 80 __ pop(edx); 81 __ pop(edi); 82} 83 84 85static void GenerateTailCallToSharedCode(MacroAssembler* masm) { 86 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 87 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kCodeOffset)); 88 __ lea(eax, FieldOperand(eax, Code::kHeaderSize)); 89 __ jmp(eax); 90} 91 92 93static void GenerateTailCallToReturnedCode(MacroAssembler* masm) { 94 __ lea(eax, FieldOperand(eax, Code::kHeaderSize)); 95 __ jmp(eax); 96} 97 98 99void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) { 100 // Checking whether the queued function is ready for install is optional, 101 // since we come across interrupts and stack checks elsewhere. However, 102 // not checking may delay installing ready functions, and always checking 103 // would be quite expensive. A good compromise is to first check against 104 // stack limit as a cue for an interrupt signal. 105 Label ok; 106 ExternalReference stack_limit = 107 ExternalReference::address_of_stack_limit(masm->isolate()); 108 __ cmp(esp, Operand::StaticVariable(stack_limit)); 109 __ j(above_equal, &ok, Label::kNear); 110 111 CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode); 112 GenerateTailCallToReturnedCode(masm); 113 114 __ bind(&ok); 115 GenerateTailCallToSharedCode(masm); 116} 117 118 119static void Generate_JSConstructStubHelper(MacroAssembler* masm, 120 bool is_api_function, 121 bool create_implicit_receiver) { 122 // ----------- S t a t e ------------- 123 // -- eax: number of arguments 124 // -- edi: constructor function 125 // -- ebx: allocation site or undefined 126 // -- edx: new target 127 // ----------------------------------- 128 129 // Enter a construct frame. 130 { 131 FrameScope scope(masm, StackFrame::CONSTRUCT); 132 133 // Preserve the incoming parameters on the stack. 134 __ AssertUndefinedOrAllocationSite(ebx); 135 __ push(ebx); 136 __ SmiTag(eax); 137 __ push(eax); 138 139 if (create_implicit_receiver) { 140 __ push(edi); 141 __ push(edx); 142 143 // Try to allocate the object without transitioning into C code. If any of 144 // the preconditions is not met, the code bails out to the runtime call. 145 Label rt_call, allocated; 146 if (FLAG_inline_new) { 147 // Verify that the new target is a JSFunction. 148 __ CmpObjectType(edx, JS_FUNCTION_TYPE, ebx); 149 __ j(not_equal, &rt_call); 150 151 // Load the initial map and verify that it is in fact a map. 152 // edx: new target 153 __ mov(eax, 154 FieldOperand(edx, JSFunction::kPrototypeOrInitialMapOffset)); 155 // Will both indicate a NULL and a Smi 156 __ JumpIfSmi(eax, &rt_call); 157 // edi: constructor 158 // eax: initial map (if proven valid below) 159 __ CmpObjectType(eax, MAP_TYPE, ebx); 160 __ j(not_equal, &rt_call); 161 162 // Fall back to runtime if the expected base constructor and base 163 // constructor differ. 164 __ cmp(edi, FieldOperand(eax, Map::kConstructorOrBackPointerOffset)); 165 __ j(not_equal, &rt_call); 166 167 // Check that the constructor is not constructing a JSFunction (see 168 // comments in Runtime_NewObject in runtime.cc). In which case the 169 // initial map's instance type would be JS_FUNCTION_TYPE. 170 // edi: constructor 171 // eax: initial map 172 __ CmpInstanceType(eax, JS_FUNCTION_TYPE); 173 __ j(equal, &rt_call); 174 175 // Now allocate the JSObject on the heap. 176 // edi: constructor 177 // eax: initial map 178 __ movzx_b(edi, FieldOperand(eax, Map::kInstanceSizeOffset)); 179 __ shl(edi, kPointerSizeLog2); 180 181 __ Allocate(edi, ebx, edi, no_reg, &rt_call, NO_ALLOCATION_FLAGS); 182 183 Factory* factory = masm->isolate()->factory(); 184 185 // Allocated the JSObject, now initialize the fields. 186 // eax: initial map 187 // ebx: JSObject (not HeapObject tagged - the actual address). 188 // edi: start of next object 189 __ mov(Operand(ebx, JSObject::kMapOffset), eax); 190 __ mov(ecx, factory->empty_fixed_array()); 191 __ mov(Operand(ebx, JSObject::kPropertiesOffset), ecx); 192 __ mov(Operand(ebx, JSObject::kElementsOffset), ecx); 193 __ lea(ecx, Operand(ebx, JSObject::kHeaderSize)); 194 195 // Add the object tag to make the JSObject real, so that we can continue 196 // and jump into the continuation code at any time from now on. 197 __ or_(ebx, Immediate(kHeapObjectTag)); 198 199 // Fill all the in-object properties with the appropriate filler. 200 // ebx: JSObject (tagged) 201 // ecx: First in-object property of JSObject (not tagged) 202 __ mov(edx, factory->undefined_value()); 203 204 if (!is_api_function) { 205 Label no_inobject_slack_tracking; 206 207 // The code below relies on these assumptions. 208 STATIC_ASSERT(Map::kNoSlackTracking == 0); 209 STATIC_ASSERT(Map::ConstructionCounter::kNext == 32); 210 // Check if slack tracking is enabled. 211 __ mov(esi, FieldOperand(eax, Map::kBitField3Offset)); 212 __ shr(esi, Map::ConstructionCounter::kShift); 213 __ j(zero, &no_inobject_slack_tracking); // Map::kNoSlackTracking 214 __ push(esi); // Save allocation count value. 215 // Decrease generous allocation count. 216 __ sub(FieldOperand(eax, Map::kBitField3Offset), 217 Immediate(1 << Map::ConstructionCounter::kShift)); 218 219 // Allocate object with a slack. 220 __ movzx_b(esi, FieldOperand(eax, Map::kUnusedPropertyFieldsOffset)); 221 __ neg(esi); 222 __ lea(esi, Operand(edi, esi, times_pointer_size, 0)); 223 // esi: offset of first field after pre-allocated fields 224 if (FLAG_debug_code) { 225 __ cmp(ecx, esi); 226 __ Assert(less_equal, 227 kUnexpectedNumberOfPreAllocatedPropertyFields); 228 } 229 __ InitializeFieldsWithFiller(ecx, esi, edx); 230 231 // To allow truncation fill the remaining fields with one pointer 232 // filler map. 233 __ mov(edx, factory->one_pointer_filler_map()); 234 __ InitializeFieldsWithFiller(ecx, edi, edx); 235 236 __ pop(esi); // Restore allocation count value before decreasing. 237 __ cmp(esi, Map::kSlackTrackingCounterEnd); 238 __ j(not_equal, &allocated); 239 240 // Push the object to the stack, and then the initial map as 241 // an argument to the runtime call. 242 __ push(ebx); 243 __ push(eax); // initial map 244 __ CallRuntime(Runtime::kFinalizeInstanceSize); 245 __ pop(ebx); 246 247 // Continue with JSObject being successfully allocated 248 // ebx: JSObject (tagged) 249 __ jmp(&allocated); 250 251 __ bind(&no_inobject_slack_tracking); 252 } 253 254 __ InitializeFieldsWithFiller(ecx, edi, edx); 255 256 // Continue with JSObject being successfully allocated 257 // ebx: JSObject (tagged) 258 __ jmp(&allocated); 259 } 260 261 // Allocate the new receiver object using the runtime call. 262 // edx: new target 263 __ bind(&rt_call); 264 int offset = kPointerSize; 265 266 // Must restore esi (context) and edi (constructor) before calling 267 // runtime. 268 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 269 __ mov(edi, Operand(esp, offset)); 270 __ push(edi); // constructor function 271 __ push(edx); // new target 272 __ CallRuntime(Runtime::kNewObject); 273 __ mov(ebx, eax); // store result in ebx 274 275 // New object allocated. 276 // ebx: newly allocated object 277 __ bind(&allocated); 278 279 // Restore the parameters. 280 __ pop(edx); // new.target 281 __ pop(edi); // Constructor function. 282 283 // Retrieve smi-tagged arguments count from the stack. 284 __ mov(eax, Operand(esp, 0)); 285 } 286 287 __ SmiUntag(eax); 288 289 if (create_implicit_receiver) { 290 // Push the allocated receiver to the stack. We need two copies 291 // because we may have to return the original one and the calling 292 // conventions dictate that the called function pops the receiver. 293 __ push(ebx); 294 __ push(ebx); 295 } else { 296 __ PushRoot(Heap::kTheHoleValueRootIndex); 297 } 298 299 // Set up pointer to last argument. 300 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); 301 302 // Copy arguments and receiver to the expression stack. 303 Label loop, entry; 304 __ mov(ecx, eax); 305 __ jmp(&entry); 306 __ bind(&loop); 307 __ push(Operand(ebx, ecx, times_4, 0)); 308 __ bind(&entry); 309 __ dec(ecx); 310 __ j(greater_equal, &loop); 311 312 // Call the function. 313 if (is_api_function) { 314 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 315 Handle<Code> code = 316 masm->isolate()->builtins()->HandleApiCallConstruct(); 317 __ call(code, RelocInfo::CODE_TARGET); 318 } else { 319 ParameterCount actual(eax); 320 __ InvokeFunction(edi, edx, actual, CALL_FUNCTION, 321 CheckDebugStepCallWrapper()); 322 } 323 324 // Store offset of return address for deoptimizer. 325 if (create_implicit_receiver && !is_api_function) { 326 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); 327 } 328 329 // Restore context from the frame. 330 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 331 332 if (create_implicit_receiver) { 333 // If the result is an object (in the ECMA sense), we should get rid 334 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 335 // on page 74. 336 Label use_receiver, exit; 337 338 // If the result is a smi, it is *not* an object in the ECMA sense. 339 __ JumpIfSmi(eax, &use_receiver); 340 341 // If the type of the result (stored in its map) is less than 342 // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense. 343 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx); 344 __ j(above_equal, &exit); 345 346 // Throw away the result of the constructor invocation and use the 347 // on-stack receiver as the result. 348 __ bind(&use_receiver); 349 __ mov(eax, Operand(esp, 0)); 350 351 // Restore the arguments count and leave the construct frame. The 352 // arguments count is stored below the receiver. 353 __ bind(&exit); 354 __ mov(ebx, Operand(esp, 1 * kPointerSize)); 355 } else { 356 __ mov(ebx, Operand(esp, 0)); 357 } 358 359 // Leave construct frame. 360 } 361 362 // Remove caller arguments from the stack and return. 363 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 364 __ pop(ecx); 365 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver 366 __ push(ecx); 367 if (create_implicit_receiver) { 368 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); 369 } 370 __ ret(0); 371} 372 373 374void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { 375 Generate_JSConstructStubHelper(masm, false, true); 376} 377 378 379void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { 380 Generate_JSConstructStubHelper(masm, true, true); 381} 382 383 384void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) { 385 Generate_JSConstructStubHelper(masm, false, false); 386} 387 388 389void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) { 390 FrameScope scope(masm, StackFrame::INTERNAL); 391 __ push(edi); 392 __ CallRuntime(Runtime::kThrowConstructedNonConstructable); 393} 394 395 396enum IsTagged { kEaxIsSmiTagged, kEaxIsUntaggedInt }; 397 398 399// Clobbers ecx, edx, edi; preserves all other registers. 400static void Generate_CheckStackOverflow(MacroAssembler* masm, 401 IsTagged eax_is_tagged) { 402 // eax : the number of items to be pushed to the stack 403 // 404 // Check the stack for overflow. We are not trying to catch 405 // interruptions (e.g. debug break and preemption) here, so the "real stack 406 // limit" is checked. 407 Label okay; 408 ExternalReference real_stack_limit = 409 ExternalReference::address_of_real_stack_limit(masm->isolate()); 410 __ mov(edi, Operand::StaticVariable(real_stack_limit)); 411 // Make ecx the space we have left. The stack might already be overflowed 412 // here which will cause ecx to become negative. 413 __ mov(ecx, esp); 414 __ sub(ecx, edi); 415 // Make edx the space we need for the array when it is unrolled onto the 416 // stack. 417 __ mov(edx, eax); 418 int smi_tag = eax_is_tagged == kEaxIsSmiTagged ? kSmiTagSize : 0; 419 __ shl(edx, kPointerSizeLog2 - smi_tag); 420 // Check if the arguments will overflow the stack. 421 __ cmp(ecx, edx); 422 __ j(greater, &okay); // Signed comparison. 423 424 // Out of stack space. 425 __ CallRuntime(Runtime::kThrowStackOverflow); 426 427 __ bind(&okay); 428} 429 430 431static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, 432 bool is_construct) { 433 ProfileEntryHookStub::MaybeCallEntryHook(masm); 434 435 // Clear the context before we push it when entering the internal frame. 436 __ Move(esi, Immediate(0)); 437 438 { 439 FrameScope scope(masm, StackFrame::INTERNAL); 440 441 // Setup the context (we need to use the caller context from the isolate). 442 ExternalReference context_address(Isolate::kContextAddress, 443 masm->isolate()); 444 __ mov(esi, Operand::StaticVariable(context_address)); 445 446 // Load the previous frame pointer (ebx) to access C arguments 447 __ mov(ebx, Operand(ebp, 0)); 448 449 // Push the function and the receiver onto the stack. 450 __ push(Operand(ebx, EntryFrameConstants::kFunctionArgOffset)); 451 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset)); 452 453 // Load the number of arguments and setup pointer to the arguments. 454 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset)); 455 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset)); 456 457 // Check if we have enough stack space to push all arguments. 458 // Expects argument count in eax. Clobbers ecx, edx, edi. 459 Generate_CheckStackOverflow(masm, kEaxIsUntaggedInt); 460 461 // Copy arguments to the stack in a loop. 462 Label loop, entry; 463 __ Move(ecx, Immediate(0)); 464 __ jmp(&entry, Label::kNear); 465 __ bind(&loop); 466 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv 467 __ push(Operand(edx, 0)); // dereference handle 468 __ inc(ecx); 469 __ bind(&entry); 470 __ cmp(ecx, eax); 471 __ j(not_equal, &loop); 472 473 // Load the previous frame pointer (ebx) to access C arguments 474 __ mov(ebx, Operand(ebp, 0)); 475 476 // Get the new.target and function from the frame. 477 __ mov(edx, Operand(ebx, EntryFrameConstants::kNewTargetArgOffset)); 478 __ mov(edi, Operand(ebx, EntryFrameConstants::kFunctionArgOffset)); 479 480 // Invoke the code. 481 Handle<Code> builtin = is_construct 482 ? masm->isolate()->builtins()->Construct() 483 : masm->isolate()->builtins()->Call(); 484 __ Call(builtin, RelocInfo::CODE_TARGET); 485 486 // Exit the internal frame. Notice that this also removes the empty. 487 // context and the function left on the stack by the code 488 // invocation. 489 } 490 __ ret(kPointerSize); // Remove receiver. 491} 492 493 494void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { 495 Generate_JSEntryTrampolineHelper(masm, false); 496} 497 498 499void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { 500 Generate_JSEntryTrampolineHelper(masm, true); 501} 502 503 504// Generate code for entering a JS function with the interpreter. 505// On entry to the function the receiver and arguments have been pushed on the 506// stack left to right. The actual argument count matches the formal parameter 507// count expected by the function. 508// 509// The live registers are: 510// o edi: the JS function object being called 511// o edx: the new target 512// o esi: our context 513// o ebp: the caller's frame pointer 514// o esp: stack pointer (pointing to return address) 515// 516// The function builds a JS frame. Please see JavaScriptFrameConstants in 517// frames-ia32.h for its layout. 518// TODO(rmcilroy): We will need to include the current bytecode pointer in the 519// frame. 520void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { 521 // Open a frame scope to indicate that there is a frame on the stack. The 522 // MANUAL indicates that the scope shouldn't actually generate code to set up 523 // the frame (that is done below). 524 FrameScope frame_scope(masm, StackFrame::MANUAL); 525 __ push(ebp); // Caller's frame pointer. 526 __ mov(ebp, esp); 527 __ push(esi); // Callee's context. 528 __ push(edi); // Callee's JS function. 529 __ push(edx); // Callee's new target. 530 531 // Push zero for bytecode array offset. 532 __ push(Immediate(0)); 533 534 // Get the bytecode array from the function object and load the pointer to the 535 // first entry into edi (InterpreterBytecodeRegister). 536 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 537 __ mov(kInterpreterBytecodeArrayRegister, 538 FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset)); 539 540 if (FLAG_debug_code) { 541 // Check function data field is actually a BytecodeArray object. 542 __ AssertNotSmi(kInterpreterBytecodeArrayRegister); 543 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE, 544 eax); 545 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry); 546 } 547 548 // Allocate the local and temporary register file on the stack. 549 { 550 // Load frame size from the BytecodeArray object. 551 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister, 552 BytecodeArray::kFrameSizeOffset)); 553 554 // Do a stack check to ensure we don't go over the limit. 555 Label ok; 556 __ mov(ecx, esp); 557 __ sub(ecx, ebx); 558 ExternalReference stack_limit = 559 ExternalReference::address_of_real_stack_limit(masm->isolate()); 560 __ cmp(ecx, Operand::StaticVariable(stack_limit)); 561 __ j(above_equal, &ok); 562 __ CallRuntime(Runtime::kThrowStackOverflow); 563 __ bind(&ok); 564 565 // If ok, push undefined as the initial value for all register file entries. 566 Label loop_header; 567 Label loop_check; 568 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value())); 569 __ jmp(&loop_check); 570 __ bind(&loop_header); 571 // TODO(rmcilroy): Consider doing more than one push per loop iteration. 572 __ push(eax); 573 // Continue loop if not done. 574 __ bind(&loop_check); 575 __ sub(ebx, Immediate(kPointerSize)); 576 __ j(greater_equal, &loop_header); 577 } 578 579 // TODO(rmcilroy): List of things not currently dealt with here but done in 580 // fullcodegen's prologue: 581 // - Support profiler (specifically profiling_counter). 582 // - Call ProfileEntryHookStub when isolate has a function_entry_hook. 583 // - Allow simulator stop operations if FLAG_stop_at is set. 584 // - Code aging of the BytecodeArray object. 585 586 // Perform stack guard check. 587 { 588 Label ok; 589 ExternalReference stack_limit = 590 ExternalReference::address_of_stack_limit(masm->isolate()); 591 __ cmp(esp, Operand::StaticVariable(stack_limit)); 592 __ j(above_equal, &ok); 593 __ push(kInterpreterBytecodeArrayRegister); 594 __ CallRuntime(Runtime::kStackGuard); 595 __ pop(kInterpreterBytecodeArrayRegister); 596 __ bind(&ok); 597 } 598 599 // Load accumulator, register file, bytecode offset, dispatch table into 600 // registers. 601 __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex); 602 __ mov(kInterpreterRegisterFileRegister, ebp); 603 __ add(kInterpreterRegisterFileRegister, 604 Immediate(InterpreterFrameConstants::kRegisterFilePointerFromFp)); 605 __ mov(kInterpreterBytecodeOffsetRegister, 606 Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag)); 607 // Since the dispatch table root might be set after builtins are generated, 608 // load directly from the roots table. 609 __ LoadRoot(ebx, Heap::kInterpreterTableRootIndex); 610 __ add(ebx, Immediate(FixedArray::kHeaderSize - kHeapObjectTag)); 611 612 // Push dispatch table as a stack located parameter to the bytecode handler. 613 DCHECK_EQ(-1, kInterpreterDispatchTableSpillSlot); 614 __ push(ebx); 615 616 // Dispatch to the first bytecode handler for the function. 617 __ movzx_b(eax, Operand(kInterpreterBytecodeArrayRegister, 618 kInterpreterBytecodeOffsetRegister, times_1, 0)); 619 __ mov(ebx, Operand(ebx, eax, times_pointer_size, 0)); 620 // Restore undefined_value in accumulator (eax) 621 // TODO(rmcilroy): Remove this once we move the dispatch table back into a 622 // register. 623 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value())); 624 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging 625 // and header removal. 626 __ add(ebx, Immediate(Code::kHeaderSize - kHeapObjectTag)); 627 __ call(ebx); 628 __ nop(); // Ensure that return address still counts as interpreter entry 629 // trampoline. 630} 631 632 633void Builtins::Generate_InterpreterExitTrampoline(MacroAssembler* masm) { 634 // TODO(rmcilroy): List of things not currently dealt with here but done in 635 // fullcodegen's EmitReturnSequence. 636 // - Supporting FLAG_trace for Runtime::TraceExit. 637 // - Support profiler (specifically decrementing profiling_counter 638 // appropriately and calling out to HandleInterrupts if necessary). 639 640 // The return value is in accumulator, which is already in rax. 641 642 // Leave the frame (also dropping the register file). 643 __ leave(); 644 645 // Drop receiver + arguments and return. 646 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister, 647 BytecodeArray::kParameterSizeOffset)); 648 __ pop(ecx); 649 __ add(esp, ebx); 650 __ push(ecx); 651 __ ret(0); 652} 653 654 655static void Generate_InterpreterPushArgs(MacroAssembler* masm, 656 Register array_limit) { 657 // ----------- S t a t e ------------- 658 // -- ebx : Pointer to the last argument in the args array. 659 // -- array_limit : Pointer to one before the first argument in the 660 // args array. 661 // ----------------------------------- 662 Label loop_header, loop_check; 663 __ jmp(&loop_check); 664 __ bind(&loop_header); 665 __ Push(Operand(ebx, 0)); 666 __ sub(ebx, Immediate(kPointerSize)); 667 __ bind(&loop_check); 668 __ cmp(ebx, array_limit); 669 __ j(greater, &loop_header, Label::kNear); 670} 671 672 673// static 674void Builtins::Generate_InterpreterPushArgsAndCall(MacroAssembler* masm) { 675 // ----------- S t a t e ------------- 676 // -- eax : the number of arguments (not including the receiver) 677 // -- ebx : the address of the first argument to be pushed. Subsequent 678 // arguments should be consecutive above this, in the same order as 679 // they are to be pushed onto the stack. 680 // -- edi : the target to call (can be any Object). 681 // ----------------------------------- 682 683 // Pop return address to allow tail-call after pushing arguments. 684 __ Pop(edx); 685 686 // Find the address of the last argument. 687 __ mov(ecx, eax); 688 __ add(ecx, Immediate(1)); // Add one for receiver. 689 __ shl(ecx, kPointerSizeLog2); 690 __ neg(ecx); 691 __ add(ecx, ebx); 692 693 Generate_InterpreterPushArgs(masm, ecx); 694 695 // Call the target. 696 __ Push(edx); // Re-push return address. 697 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); 698} 699 700 701// static 702void Builtins::Generate_InterpreterPushArgsAndConstruct(MacroAssembler* masm) { 703 // ----------- S t a t e ------------- 704 // -- eax : the number of arguments (not including the receiver) 705 // -- edx : the new target 706 // -- edi : the constructor 707 // -- ebx : the address of the first argument to be pushed. Subsequent 708 // arguments should be consecutive above this, in the same order as 709 // they are to be pushed onto the stack. 710 // ----------------------------------- 711 712 // Save number of arguments on the stack below where arguments are going 713 // to be pushed. 714 __ mov(ecx, eax); 715 __ neg(ecx); 716 __ mov(Operand(esp, ecx, times_pointer_size, -kPointerSize), eax); 717 __ mov(eax, ecx); 718 719 // Pop return address to allow tail-call after pushing arguments. 720 __ Pop(ecx); 721 722 // Find the address of the last argument. 723 __ shl(eax, kPointerSizeLog2); 724 __ add(eax, ebx); 725 726 // Push padding for receiver. 727 __ Push(Immediate(0)); 728 729 Generate_InterpreterPushArgs(masm, eax); 730 731 // Restore number of arguments from slot on stack. 732 __ mov(eax, Operand(esp, -kPointerSize)); 733 734 // Re-push return address. 735 __ Push(ecx); 736 737 // Call the constructor with unmodified eax, edi, ebi values. 738 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); 739} 740 741 742static void Generate_InterpreterNotifyDeoptimizedHelper( 743 MacroAssembler* masm, Deoptimizer::BailoutType type) { 744 // Enter an internal frame. 745 { 746 FrameScope scope(masm, StackFrame::INTERNAL); 747 __ Push(kInterpreterAccumulatorRegister); // Save accumulator register. 748 749 // Pass the deoptimization type to the runtime system. 750 __ Push(Smi::FromInt(static_cast<int>(type))); 751 752 __ CallRuntime(Runtime::kNotifyDeoptimized); 753 754 __ Pop(kInterpreterAccumulatorRegister); // Restore accumulator register. 755 // Tear down internal frame. 756 } 757 758 // Initialize register file register. 759 __ mov(kInterpreterRegisterFileRegister, ebp); 760 __ add(kInterpreterRegisterFileRegister, 761 Immediate(InterpreterFrameConstants::kRegisterFilePointerFromFp)); 762 763 // Get the bytecode array pointer from the frame. 764 __ mov(ebx, Operand(kInterpreterRegisterFileRegister, 765 InterpreterFrameConstants::kFunctionFromRegisterPointer)); 766 __ mov(ebx, FieldOperand(ebx, JSFunction::kSharedFunctionInfoOffset)); 767 __ mov(kInterpreterBytecodeArrayRegister, 768 FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset)); 769 770 if (FLAG_debug_code) { 771 // Check function data field is actually a BytecodeArray object. 772 __ AssertNotSmi(kInterpreterBytecodeArrayRegister); 773 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE, 774 ebx); 775 __ Assert(equal, kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry); 776 } 777 778 // Get the target bytecode offset from the frame. 779 __ mov( 780 kInterpreterBytecodeOffsetRegister, 781 Operand(kInterpreterRegisterFileRegister, 782 InterpreterFrameConstants::kBytecodeOffsetFromRegisterPointer)); 783 __ SmiUntag(kInterpreterBytecodeOffsetRegister); 784 785 // Push dispatch table as a stack located parameter to the bytecode handler - 786 // overwrite the state slot (we don't use these for interpreter deopts). 787 __ LoadRoot(ebx, Heap::kInterpreterTableRootIndex); 788 __ add(ebx, Immediate(FixedArray::kHeaderSize - kHeapObjectTag)); 789 DCHECK_EQ(-1, kInterpreterDispatchTableSpillSlot); 790 __ mov(Operand(esp, kPointerSize), ebx); 791 792 // Dispatch to the target bytecode. 793 __ movzx_b(esi, Operand(kInterpreterBytecodeArrayRegister, 794 kInterpreterBytecodeOffsetRegister, times_1, 0)); 795 __ mov(ebx, Operand(ebx, esi, times_pointer_size, 0)); 796 797 // Get the context from the frame. 798 // TODO(rmcilroy): Update interpreter frame to expect current context at the 799 // context slot instead of the function context. 800 __ mov(kContextRegister, 801 Operand(kInterpreterRegisterFileRegister, 802 InterpreterFrameConstants::kContextFromRegisterPointer)); 803 804 // TODO(rmcilroy): Make dispatch table point to code entrys to avoid untagging 805 // and header removal. 806 __ add(ebx, Immediate(Code::kHeaderSize - kHeapObjectTag)); 807 __ jmp(ebx); 808} 809 810 811void Builtins::Generate_InterpreterNotifyDeoptimized(MacroAssembler* masm) { 812 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::EAGER); 813} 814 815 816void Builtins::Generate_InterpreterNotifySoftDeoptimized(MacroAssembler* masm) { 817 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::SOFT); 818} 819 820 821void Builtins::Generate_InterpreterNotifyLazyDeoptimized(MacroAssembler* masm) { 822 Generate_InterpreterNotifyDeoptimizedHelper(masm, Deoptimizer::LAZY); 823} 824 825 826void Builtins::Generate_CompileLazy(MacroAssembler* masm) { 827 CallRuntimePassFunction(masm, Runtime::kCompileLazy); 828 GenerateTailCallToReturnedCode(masm); 829} 830 831 832void Builtins::Generate_CompileOptimized(MacroAssembler* masm) { 833 CallRuntimePassFunction(masm, Runtime::kCompileOptimized_NotConcurrent); 834 GenerateTailCallToReturnedCode(masm); 835} 836 837 838void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) { 839 CallRuntimePassFunction(masm, Runtime::kCompileOptimized_Concurrent); 840 GenerateTailCallToReturnedCode(masm); 841} 842 843 844static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) { 845 // For now, we are relying on the fact that make_code_young doesn't do any 846 // garbage collection which allows us to save/restore the registers without 847 // worrying about which of them contain pointers. We also don't build an 848 // internal frame to make the code faster, since we shouldn't have to do stack 849 // crawls in MakeCodeYoung. This seems a bit fragile. 850 851 // Re-execute the code that was patched back to the young age when 852 // the stub returns. 853 __ sub(Operand(esp, 0), Immediate(5)); 854 __ pushad(); 855 __ mov(eax, Operand(esp, 8 * kPointerSize)); 856 { 857 FrameScope scope(masm, StackFrame::MANUAL); 858 __ PrepareCallCFunction(2, ebx); 859 __ mov(Operand(esp, 1 * kPointerSize), 860 Immediate(ExternalReference::isolate_address(masm->isolate()))); 861 __ mov(Operand(esp, 0), eax); 862 __ CallCFunction( 863 ExternalReference::get_make_code_young_function(masm->isolate()), 2); 864 } 865 __ popad(); 866 __ ret(0); 867} 868 869#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C) \ 870void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking( \ 871 MacroAssembler* masm) { \ 872 GenerateMakeCodeYoungAgainCommon(masm); \ 873} \ 874void Builtins::Generate_Make##C##CodeYoungAgainOddMarking( \ 875 MacroAssembler* masm) { \ 876 GenerateMakeCodeYoungAgainCommon(masm); \ 877} 878CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR) 879#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR 880 881 882void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) { 883 // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact 884 // that make_code_young doesn't do any garbage collection which allows us to 885 // save/restore the registers without worrying about which of them contain 886 // pointers. 887 __ pushad(); 888 __ mov(eax, Operand(esp, 8 * kPointerSize)); 889 __ sub(eax, Immediate(Assembler::kCallInstructionLength)); 890 { // NOLINT 891 FrameScope scope(masm, StackFrame::MANUAL); 892 __ PrepareCallCFunction(2, ebx); 893 __ mov(Operand(esp, 1 * kPointerSize), 894 Immediate(ExternalReference::isolate_address(masm->isolate()))); 895 __ mov(Operand(esp, 0), eax); 896 __ CallCFunction( 897 ExternalReference::get_mark_code_as_executed_function(masm->isolate()), 898 2); 899 } 900 __ popad(); 901 902 // Perform prologue operations usually performed by the young code stub. 903 __ pop(eax); // Pop return address into scratch register. 904 __ push(ebp); // Caller's frame pointer. 905 __ mov(ebp, esp); 906 __ push(esi); // Callee's context. 907 __ push(edi); // Callee's JS Function. 908 __ push(eax); // Push return address after frame prologue. 909 910 // Jump to point after the code-age stub. 911 __ ret(0); 912} 913 914 915void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) { 916 GenerateMakeCodeYoungAgainCommon(masm); 917} 918 919 920void Builtins::Generate_MarkCodeAsToBeExecutedOnce(MacroAssembler* masm) { 921 Generate_MarkCodeAsExecutedOnce(masm); 922} 923 924 925static void Generate_NotifyStubFailureHelper(MacroAssembler* masm, 926 SaveFPRegsMode save_doubles) { 927 // Enter an internal frame. 928 { 929 FrameScope scope(masm, StackFrame::INTERNAL); 930 931 // Preserve registers across notification, this is important for compiled 932 // stubs that tail call the runtime on deopts passing their parameters in 933 // registers. 934 __ pushad(); 935 __ CallRuntime(Runtime::kNotifyStubFailure, save_doubles); 936 __ popad(); 937 // Tear down internal frame. 938 } 939 940 __ pop(MemOperand(esp, 0)); // Ignore state offset 941 __ ret(0); // Return to IC Miss stub, continuation still on stack. 942} 943 944 945void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) { 946 Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs); 947} 948 949 950void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) { 951 Generate_NotifyStubFailureHelper(masm, kSaveFPRegs); 952} 953 954 955static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm, 956 Deoptimizer::BailoutType type) { 957 { 958 FrameScope scope(masm, StackFrame::INTERNAL); 959 960 // Pass deoptimization type to the runtime system. 961 __ push(Immediate(Smi::FromInt(static_cast<int>(type)))); 962 __ CallRuntime(Runtime::kNotifyDeoptimized); 963 964 // Tear down internal frame. 965 } 966 967 // Get the full codegen state from the stack and untag it. 968 __ mov(ecx, Operand(esp, 1 * kPointerSize)); 969 __ SmiUntag(ecx); 970 971 // Switch on the state. 972 Label not_no_registers, not_tos_eax; 973 __ cmp(ecx, FullCodeGenerator::NO_REGISTERS); 974 __ j(not_equal, ¬_no_registers, Label::kNear); 975 __ ret(1 * kPointerSize); // Remove state. 976 977 __ bind(¬_no_registers); 978 __ mov(eax, Operand(esp, 2 * kPointerSize)); 979 __ cmp(ecx, FullCodeGenerator::TOS_REG); 980 __ j(not_equal, ¬_tos_eax, Label::kNear); 981 __ ret(2 * kPointerSize); // Remove state, eax. 982 983 __ bind(¬_tos_eax); 984 __ Abort(kNoCasesLeft); 985} 986 987 988void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) { 989 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER); 990} 991 992 993void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) { 994 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT); 995} 996 997 998void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) { 999 Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY); 1000} 1001 1002 1003// static 1004void Builtins::Generate_DatePrototype_GetField(MacroAssembler* masm, 1005 int field_index) { 1006 // ----------- S t a t e ------------- 1007 // -- esp[0] : return address 1008 // -- esp[4] : receiver 1009 // ----------------------------------- 1010 1011 // 1. Load receiver into eax and check that it's actually a JSDate object. 1012 Label receiver_not_date; 1013 { 1014 __ mov(eax, Operand(esp, kPointerSize)); 1015 __ JumpIfSmi(eax, &receiver_not_date); 1016 __ CmpObjectType(eax, JS_DATE_TYPE, ebx); 1017 __ j(not_equal, &receiver_not_date); 1018 } 1019 1020 // 2. Load the specified date field, falling back to the runtime as necessary. 1021 if (field_index == JSDate::kDateValue) { 1022 __ mov(eax, FieldOperand(eax, JSDate::kValueOffset)); 1023 } else { 1024 if (field_index < JSDate::kFirstUncachedField) { 1025 Label stamp_mismatch; 1026 __ mov(edx, Operand::StaticVariable( 1027 ExternalReference::date_cache_stamp(masm->isolate()))); 1028 __ cmp(edx, FieldOperand(eax, JSDate::kCacheStampOffset)); 1029 __ j(not_equal, &stamp_mismatch, Label::kNear); 1030 __ mov(eax, FieldOperand( 1031 eax, JSDate::kValueOffset + field_index * kPointerSize)); 1032 __ ret(1 * kPointerSize); 1033 __ bind(&stamp_mismatch); 1034 } 1035 FrameScope scope(masm, StackFrame::INTERNAL); 1036 __ PrepareCallCFunction(2, ebx); 1037 __ mov(Operand(esp, 0), eax); 1038 __ mov(Operand(esp, 1 * kPointerSize), 1039 Immediate(Smi::FromInt(field_index))); 1040 __ CallCFunction( 1041 ExternalReference::get_date_field_function(masm->isolate()), 2); 1042 } 1043 __ ret(1 * kPointerSize); 1044 1045 // 3. Raise a TypeError if the receiver is not a date. 1046 __ bind(&receiver_not_date); 1047 { 1048 FrameScope scope(masm, StackFrame::MANUAL); 1049 __ EnterFrame(StackFrame::INTERNAL); 1050 __ CallRuntime(Runtime::kThrowNotDateError); 1051 } 1052} 1053 1054 1055// static 1056void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) { 1057 // ----------- S t a t e ------------- 1058 // -- eax : argc 1059 // -- esp[0] : return address 1060 // -- esp[4] : argArray 1061 // -- esp[8] : thisArg 1062 // -- esp[12] : receiver 1063 // ----------------------------------- 1064 1065 // 1. Load receiver into edi, argArray into eax (if present), remove all 1066 // arguments from the stack (including the receiver), and push thisArg (if 1067 // present) instead. 1068 { 1069 Label no_arg_array, no_this_arg; 1070 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); 1071 __ mov(ebx, edx); 1072 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); 1073 __ test(eax, eax); 1074 __ j(zero, &no_this_arg, Label::kNear); 1075 { 1076 __ mov(edx, Operand(esp, eax, times_pointer_size, 0)); 1077 __ cmp(eax, Immediate(1)); 1078 __ j(equal, &no_arg_array, Label::kNear); 1079 __ mov(ebx, Operand(esp, eax, times_pointer_size, -kPointerSize)); 1080 __ bind(&no_arg_array); 1081 } 1082 __ bind(&no_this_arg); 1083 __ PopReturnAddressTo(ecx); 1084 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); 1085 __ Push(edx); 1086 __ PushReturnAddressFrom(ecx); 1087 __ Move(eax, ebx); 1088 } 1089 1090 // ----------- S t a t e ------------- 1091 // -- eax : argArray 1092 // -- edi : receiver 1093 // -- esp[0] : return address 1094 // -- esp[4] : thisArg 1095 // ----------------------------------- 1096 1097 // 2. Make sure the receiver is actually callable. 1098 Label receiver_not_callable; 1099 __ JumpIfSmi(edi, &receiver_not_callable, Label::kNear); 1100 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); 1101 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable); 1102 __ j(zero, &receiver_not_callable, Label::kNear); 1103 1104 // 3. Tail call with no arguments if argArray is null or undefined. 1105 Label no_arguments; 1106 __ JumpIfRoot(eax, Heap::kNullValueRootIndex, &no_arguments, Label::kNear); 1107 __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &no_arguments, 1108 Label::kNear); 1109 1110 // 4a. Apply the receiver to the given argArray (passing undefined for 1111 // new.target). 1112 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); 1113 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); 1114 1115 // 4b. The argArray is either null or undefined, so we tail call without any 1116 // arguments to the receiver. 1117 __ bind(&no_arguments); 1118 { 1119 __ Set(eax, 0); 1120 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); 1121 } 1122 1123 // 4c. The receiver is not callable, throw an appropriate TypeError. 1124 __ bind(&receiver_not_callable); 1125 { 1126 __ mov(Operand(esp, kPointerSize), edi); 1127 __ TailCallRuntime(Runtime::kThrowApplyNonFunction); 1128 } 1129} 1130 1131 1132// static 1133void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { 1134 // Stack Layout: 1135 // esp[0] : Return address 1136 // esp[8] : Argument n 1137 // esp[16] : Argument n-1 1138 // ... 1139 // esp[8 * n] : Argument 1 1140 // esp[8 * (n + 1)] : Receiver (callable to call) 1141 // 1142 // eax contains the number of arguments, n, not counting the receiver. 1143 // 1144 // 1. Make sure we have at least one argument. 1145 { 1146 Label done; 1147 __ test(eax, eax); 1148 __ j(not_zero, &done, Label::kNear); 1149 __ PopReturnAddressTo(ebx); 1150 __ PushRoot(Heap::kUndefinedValueRootIndex); 1151 __ PushReturnAddressFrom(ebx); 1152 __ inc(eax); 1153 __ bind(&done); 1154 } 1155 1156 // 2. Get the callable to call (passed as receiver) from the stack. 1157 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); 1158 1159 // 3. Shift arguments and return address one slot down on the stack 1160 // (overwriting the original receiver). Adjust argument count to make 1161 // the original first argument the new receiver. 1162 { 1163 Label loop; 1164 __ mov(ecx, eax); 1165 __ bind(&loop); 1166 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0)); 1167 __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx); 1168 __ dec(ecx); 1169 __ j(not_sign, &loop); // While non-negative (to copy return address). 1170 __ pop(ebx); // Discard copy of return address. 1171 __ dec(eax); // One fewer argument (first argument is new receiver). 1172 } 1173 1174 // 4. Call the callable. 1175 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); 1176} 1177 1178 1179void Builtins::Generate_ReflectApply(MacroAssembler* masm) { 1180 // ----------- S t a t e ------------- 1181 // -- eax : argc 1182 // -- esp[0] : return address 1183 // -- esp[4] : argumentsList 1184 // -- esp[8] : thisArgument 1185 // -- esp[12] : target 1186 // -- esp[16] : receiver 1187 // ----------------------------------- 1188 1189 // 1. Load target into edi (if present), argumentsList into eax (if present), 1190 // remove all arguments from the stack (including the receiver), and push 1191 // thisArgument (if present) instead. 1192 { 1193 Label done; 1194 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex); 1195 __ mov(edx, edi); 1196 __ mov(ebx, edi); 1197 __ cmp(eax, Immediate(1)); 1198 __ j(below, &done, Label::kNear); 1199 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize)); 1200 __ j(equal, &done, Label::kNear); 1201 __ mov(edx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize)); 1202 __ cmp(eax, Immediate(3)); 1203 __ j(below, &done, Label::kNear); 1204 __ mov(ebx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize)); 1205 __ bind(&done); 1206 __ PopReturnAddressTo(ecx); 1207 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); 1208 __ Push(edx); 1209 __ PushReturnAddressFrom(ecx); 1210 __ Move(eax, ebx); 1211 } 1212 1213 // ----------- S t a t e ------------- 1214 // -- eax : argumentsList 1215 // -- edi : target 1216 // -- esp[0] : return address 1217 // -- esp[4] : thisArgument 1218 // ----------------------------------- 1219 1220 // 2. Make sure the target is actually callable. 1221 Label target_not_callable; 1222 __ JumpIfSmi(edi, &target_not_callable, Label::kNear); 1223 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); 1224 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable); 1225 __ j(zero, &target_not_callable, Label::kNear); 1226 1227 // 3a. Apply the target to the given argumentsList (passing undefined for 1228 // new.target). 1229 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); 1230 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); 1231 1232 // 3b. The target is not callable, throw an appropriate TypeError. 1233 __ bind(&target_not_callable); 1234 { 1235 __ mov(Operand(esp, kPointerSize), edi); 1236 __ TailCallRuntime(Runtime::kThrowApplyNonFunction); 1237 } 1238} 1239 1240 1241void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { 1242 // ----------- S t a t e ------------- 1243 // -- eax : argc 1244 // -- esp[0] : return address 1245 // -- esp[4] : new.target (optional) 1246 // -- esp[8] : argumentsList 1247 // -- esp[12] : target 1248 // -- esp[16] : receiver 1249 // ----------------------------------- 1250 1251 // 1. Load target into edi (if present), argumentsList into eax (if present), 1252 // new.target into edx (if present, otherwise use target), remove all 1253 // arguments from the stack (including the receiver), and push thisArgument 1254 // (if present) instead. 1255 { 1256 Label done; 1257 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex); 1258 __ mov(edx, edi); 1259 __ mov(ebx, edi); 1260 __ cmp(eax, Immediate(1)); 1261 __ j(below, &done, Label::kNear); 1262 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize)); 1263 __ mov(edx, edi); 1264 __ j(equal, &done, Label::kNear); 1265 __ mov(ebx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize)); 1266 __ cmp(eax, Immediate(3)); 1267 __ j(below, &done, Label::kNear); 1268 __ mov(edx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize)); 1269 __ bind(&done); 1270 __ PopReturnAddressTo(ecx); 1271 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); 1272 __ PushRoot(Heap::kUndefinedValueRootIndex); 1273 __ PushReturnAddressFrom(ecx); 1274 __ Move(eax, ebx); 1275 } 1276 1277 // ----------- S t a t e ------------- 1278 // -- eax : argumentsList 1279 // -- edx : new.target 1280 // -- edi : target 1281 // -- esp[0] : return address 1282 // -- esp[4] : receiver (undefined) 1283 // ----------------------------------- 1284 1285 // 2. Make sure the target is actually a constructor. 1286 Label target_not_constructor; 1287 __ JumpIfSmi(edi, &target_not_constructor, Label::kNear); 1288 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); 1289 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor); 1290 __ j(zero, &target_not_constructor, Label::kNear); 1291 1292 // 3. Make sure the target is actually a constructor. 1293 Label new_target_not_constructor; 1294 __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear); 1295 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 1296 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor); 1297 __ j(zero, &new_target_not_constructor, Label::kNear); 1298 1299 // 4a. Construct the target with the given new.target and argumentsList. 1300 __ Jump(masm->isolate()->builtins()->Apply(), RelocInfo::CODE_TARGET); 1301 1302 // 4b. The target is not a constructor, throw an appropriate TypeError. 1303 __ bind(&target_not_constructor); 1304 { 1305 __ mov(Operand(esp, kPointerSize), edi); 1306 __ TailCallRuntime(Runtime::kThrowCalledNonCallable); 1307 } 1308 1309 // 4c. The new.target is not a constructor, throw an appropriate TypeError. 1310 __ bind(&new_target_not_constructor); 1311 { 1312 __ mov(Operand(esp, kPointerSize), edx); 1313 __ TailCallRuntime(Runtime::kThrowCalledNonCallable); 1314 } 1315} 1316 1317 1318void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) { 1319 // ----------- S t a t e ------------- 1320 // -- eax : argc 1321 // -- esp[0] : return address 1322 // -- esp[4] : last argument 1323 // ----------------------------------- 1324 Label generic_array_code; 1325 1326 // Get the InternalArray function. 1327 __ LoadGlobalFunction(Context::INTERNAL_ARRAY_FUNCTION_INDEX, edi); 1328 1329 if (FLAG_debug_code) { 1330 // Initial map for the builtin InternalArray function should be a map. 1331 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 1332 // Will both indicate a NULL and a Smi. 1333 __ test(ebx, Immediate(kSmiTagMask)); 1334 __ Assert(not_zero, kUnexpectedInitialMapForInternalArrayFunction); 1335 __ CmpObjectType(ebx, MAP_TYPE, ecx); 1336 __ Assert(equal, kUnexpectedInitialMapForInternalArrayFunction); 1337 } 1338 1339 // Run the native code for the InternalArray function called as a normal 1340 // function. 1341 // tail call a stub 1342 InternalArrayConstructorStub stub(masm->isolate()); 1343 __ TailCallStub(&stub); 1344} 1345 1346 1347void Builtins::Generate_ArrayCode(MacroAssembler* masm) { 1348 // ----------- S t a t e ------------- 1349 // -- eax : argc 1350 // -- esp[0] : return address 1351 // -- esp[4] : last argument 1352 // ----------------------------------- 1353 Label generic_array_code; 1354 1355 // Get the Array function. 1356 __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, edi); 1357 __ mov(edx, edi); 1358 1359 if (FLAG_debug_code) { 1360 // Initial map for the builtin Array function should be a map. 1361 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 1362 // Will both indicate a NULL and a Smi. 1363 __ test(ebx, Immediate(kSmiTagMask)); 1364 __ Assert(not_zero, kUnexpectedInitialMapForArrayFunction); 1365 __ CmpObjectType(ebx, MAP_TYPE, ecx); 1366 __ Assert(equal, kUnexpectedInitialMapForArrayFunction); 1367 } 1368 1369 // Run the native code for the Array function called as a normal function. 1370 // tail call a stub 1371 __ mov(ebx, masm->isolate()->factory()->undefined_value()); 1372 ArrayConstructorStub stub(masm->isolate()); 1373 __ TailCallStub(&stub); 1374} 1375 1376 1377// static 1378void Builtins::Generate_NumberConstructor(MacroAssembler* masm) { 1379 // ----------- S t a t e ------------- 1380 // -- eax : number of arguments 1381 // -- edi : constructor function 1382 // -- esp[0] : return address 1383 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1384 // -- esp[(argc + 1) * 4] : receiver 1385 // ----------------------------------- 1386 1387 // 1. Load the first argument into eax and get rid of the rest (including the 1388 // receiver). 1389 Label no_arguments; 1390 { 1391 __ test(eax, eax); 1392 __ j(zero, &no_arguments, Label::kNear); 1393 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0)); 1394 __ PopReturnAddressTo(ecx); 1395 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); 1396 __ PushReturnAddressFrom(ecx); 1397 __ mov(eax, ebx); 1398 } 1399 1400 // 2a. Convert the first argument to a number. 1401 ToNumberStub stub(masm->isolate()); 1402 __ TailCallStub(&stub); 1403 1404 // 2b. No arguments, return +0 (already in eax). 1405 __ bind(&no_arguments); 1406 __ ret(1 * kPointerSize); 1407} 1408 1409 1410// static 1411void Builtins::Generate_NumberConstructor_ConstructStub(MacroAssembler* masm) { 1412 // ----------- S t a t e ------------- 1413 // -- eax : number of arguments 1414 // -- edi : constructor function 1415 // -- edx : new target 1416 // -- esp[0] : return address 1417 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1418 // -- esp[(argc + 1) * 4] : receiver 1419 // ----------------------------------- 1420 1421 // 1. Make sure we operate in the context of the called function. 1422 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 1423 1424 // 2. Load the first argument into ebx and get rid of the rest (including the 1425 // receiver). 1426 { 1427 Label no_arguments, done; 1428 __ test(eax, eax); 1429 __ j(zero, &no_arguments, Label::kNear); 1430 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0)); 1431 __ jmp(&done, Label::kNear); 1432 __ bind(&no_arguments); 1433 __ Move(ebx, Smi::FromInt(0)); 1434 __ bind(&done); 1435 __ PopReturnAddressTo(ecx); 1436 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); 1437 __ PushReturnAddressFrom(ecx); 1438 } 1439 1440 // 3. Make sure ebx is a number. 1441 { 1442 Label done_convert; 1443 __ JumpIfSmi(ebx, &done_convert); 1444 __ CompareRoot(FieldOperand(ebx, HeapObject::kMapOffset), 1445 Heap::kHeapNumberMapRootIndex); 1446 __ j(equal, &done_convert); 1447 { 1448 FrameScope scope(masm, StackFrame::INTERNAL); 1449 __ Push(edi); 1450 __ Push(edx); 1451 __ Move(eax, ebx); 1452 ToNumberStub stub(masm->isolate()); 1453 __ CallStub(&stub); 1454 __ Move(ebx, eax); 1455 __ Pop(edx); 1456 __ Pop(edi); 1457 } 1458 __ bind(&done_convert); 1459 } 1460 1461 // 4. Check if new target and constructor differ. 1462 Label new_object; 1463 __ cmp(edx, edi); 1464 __ j(not_equal, &new_object); 1465 1466 // 5. Allocate a JSValue wrapper for the number. 1467 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object); 1468 __ Ret(); 1469 1470 // 6. Fallback to the runtime to create new object. 1471 __ bind(&new_object); 1472 { 1473 FrameScope scope(masm, StackFrame::INTERNAL); 1474 __ Push(ebx); // the first argument 1475 __ Push(edi); // constructor function 1476 __ Push(edx); // new target 1477 __ CallRuntime(Runtime::kNewObject); 1478 __ Pop(FieldOperand(eax, JSValue::kValueOffset)); 1479 } 1480 __ Ret(); 1481} 1482 1483 1484// static 1485void Builtins::Generate_StringConstructor(MacroAssembler* masm) { 1486 // ----------- S t a t e ------------- 1487 // -- eax : number of arguments 1488 // -- edi : constructor function 1489 // -- esp[0] : return address 1490 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1491 // -- esp[(argc + 1) * 4] : receiver 1492 // ----------------------------------- 1493 1494 // 1. Load the first argument into eax and get rid of the rest (including the 1495 // receiver). 1496 Label no_arguments; 1497 { 1498 __ test(eax, eax); 1499 __ j(zero, &no_arguments, Label::kNear); 1500 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0)); 1501 __ PopReturnAddressTo(ecx); 1502 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); 1503 __ PushReturnAddressFrom(ecx); 1504 __ mov(eax, ebx); 1505 } 1506 1507 // 2a. At least one argument, return eax if it's a string, otherwise 1508 // dispatch to appropriate conversion. 1509 Label to_string, symbol_descriptive_string; 1510 { 1511 __ JumpIfSmi(eax, &to_string, Label::kNear); 1512 STATIC_ASSERT(FIRST_NONSTRING_TYPE == SYMBOL_TYPE); 1513 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx); 1514 __ j(above, &to_string, Label::kNear); 1515 __ j(equal, &symbol_descriptive_string, Label::kNear); 1516 __ Ret(); 1517 } 1518 1519 // 2b. No arguments, return the empty string (and pop the receiver). 1520 __ bind(&no_arguments); 1521 { 1522 __ LoadRoot(eax, Heap::kempty_stringRootIndex); 1523 __ ret(1 * kPointerSize); 1524 } 1525 1526 // 3a. Convert eax to a string. 1527 __ bind(&to_string); 1528 { 1529 ToStringStub stub(masm->isolate()); 1530 __ TailCallStub(&stub); 1531 } 1532 1533 // 3b. Convert symbol in eax to a string. 1534 __ bind(&symbol_descriptive_string); 1535 { 1536 __ PopReturnAddressTo(ecx); 1537 __ Push(eax); 1538 __ PushReturnAddressFrom(ecx); 1539 __ TailCallRuntime(Runtime::kSymbolDescriptiveString); 1540 } 1541} 1542 1543 1544// static 1545void Builtins::Generate_StringConstructor_ConstructStub(MacroAssembler* masm) { 1546 // ----------- S t a t e ------------- 1547 // -- eax : number of arguments 1548 // -- edi : constructor function 1549 // -- edx : new target 1550 // -- esp[0] : return address 1551 // -- esp[(argc - n) * 4] : arg[n] (zero-based) 1552 // -- esp[(argc + 1) * 4] : receiver 1553 // ----------------------------------- 1554 1555 // 1. Make sure we operate in the context of the called function. 1556 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 1557 1558 // 2. Load the first argument into ebx and get rid of the rest (including the 1559 // receiver). 1560 { 1561 Label no_arguments, done; 1562 __ test(eax, eax); 1563 __ j(zero, &no_arguments, Label::kNear); 1564 __ mov(ebx, Operand(esp, eax, times_pointer_size, 0)); 1565 __ jmp(&done, Label::kNear); 1566 __ bind(&no_arguments); 1567 __ LoadRoot(ebx, Heap::kempty_stringRootIndex); 1568 __ bind(&done); 1569 __ PopReturnAddressTo(ecx); 1570 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); 1571 __ PushReturnAddressFrom(ecx); 1572 } 1573 1574 // 3. Make sure ebx is a string. 1575 { 1576 Label convert, done_convert; 1577 __ JumpIfSmi(ebx, &convert, Label::kNear); 1578 __ CmpObjectType(ebx, FIRST_NONSTRING_TYPE, ecx); 1579 __ j(below, &done_convert); 1580 __ bind(&convert); 1581 { 1582 FrameScope scope(masm, StackFrame::INTERNAL); 1583 ToStringStub stub(masm->isolate()); 1584 __ Push(edi); 1585 __ Push(edx); 1586 __ Move(eax, ebx); 1587 __ CallStub(&stub); 1588 __ Move(ebx, eax); 1589 __ Pop(edx); 1590 __ Pop(edi); 1591 } 1592 __ bind(&done_convert); 1593 } 1594 1595 // 4. Check if new target and constructor differ. 1596 Label new_object; 1597 __ cmp(edx, edi); 1598 __ j(not_equal, &new_object); 1599 1600 // 5. Allocate a JSValue wrapper for the string. 1601 __ AllocateJSValue(eax, edi, ebx, ecx, &new_object); 1602 __ Ret(); 1603 1604 // 6. Fallback to the runtime to create new object. 1605 __ bind(&new_object); 1606 { 1607 FrameScope scope(masm, StackFrame::INTERNAL); 1608 __ Push(ebx); // the first argument 1609 __ Push(edi); // constructor function 1610 __ Push(edx); // new target 1611 __ CallRuntime(Runtime::kNewObject); 1612 __ Pop(FieldOperand(eax, JSValue::kValueOffset)); 1613 } 1614 __ Ret(); 1615} 1616 1617 1618static void ArgumentsAdaptorStackCheck(MacroAssembler* masm, 1619 Label* stack_overflow) { 1620 // ----------- S t a t e ------------- 1621 // -- eax : actual number of arguments 1622 // -- ebx : expected number of arguments 1623 // -- edx : new target (passed through to callee) 1624 // ----------------------------------- 1625 // Check the stack for overflow. We are not trying to catch 1626 // interruptions (e.g. debug break and preemption) here, so the "real stack 1627 // limit" is checked. 1628 ExternalReference real_stack_limit = 1629 ExternalReference::address_of_real_stack_limit(masm->isolate()); 1630 __ mov(edi, Operand::StaticVariable(real_stack_limit)); 1631 // Make ecx the space we have left. The stack might already be overflowed 1632 // here which will cause ecx to become negative. 1633 __ mov(ecx, esp); 1634 __ sub(ecx, edi); 1635 // Make edi the space we need for the array when it is unrolled onto the 1636 // stack. 1637 __ mov(edi, ebx); 1638 __ shl(edi, kPointerSizeLog2); 1639 // Check if the arguments will overflow the stack. 1640 __ cmp(ecx, edi); 1641 __ j(less_equal, stack_overflow); // Signed comparison. 1642} 1643 1644 1645static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { 1646 __ push(ebp); 1647 __ mov(ebp, esp); 1648 1649 // Store the arguments adaptor context sentinel. 1650 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 1651 1652 // Push the function on the stack. 1653 __ push(edi); 1654 1655 // Preserve the number of arguments on the stack. Must preserve eax, 1656 // ebx and ecx because these registers are used when copying the 1657 // arguments and the receiver. 1658 STATIC_ASSERT(kSmiTagSize == 1); 1659 __ lea(edi, Operand(eax, eax, times_1, kSmiTag)); 1660 __ push(edi); 1661} 1662 1663 1664static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { 1665 // Retrieve the number of arguments from the stack. 1666 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset)); 1667 1668 // Leave the frame. 1669 __ leave(); 1670 1671 // Remove caller arguments from the stack. 1672 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 1673 __ pop(ecx); 1674 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver 1675 __ push(ecx); 1676} 1677 1678 1679// static 1680void Builtins::Generate_Apply(MacroAssembler* masm) { 1681 // ----------- S t a t e ------------- 1682 // -- eax : argumentsList 1683 // -- edi : target 1684 // -- edx : new.target (checked to be constructor or undefined) 1685 // -- esp[0] : return address. 1686 // -- esp[4] : thisArgument 1687 // ----------------------------------- 1688 1689 // Create the list of arguments from the array-like argumentsList. 1690 { 1691 Label create_arguments, create_array, create_runtime, done_create; 1692 __ JumpIfSmi(eax, &create_runtime); 1693 1694 // Load the map of argumentsList into ecx. 1695 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 1696 1697 // Load native context into ebx. 1698 __ mov(ebx, NativeContextOperand()); 1699 1700 // Check if argumentsList is an (unmodified) arguments object. 1701 __ cmp(ecx, ContextOperand(ebx, Context::SLOPPY_ARGUMENTS_MAP_INDEX)); 1702 __ j(equal, &create_arguments); 1703 __ cmp(ecx, ContextOperand(ebx, Context::STRICT_ARGUMENTS_MAP_INDEX)); 1704 __ j(equal, &create_arguments); 1705 1706 // Check if argumentsList is a fast JSArray. 1707 __ CmpInstanceType(ecx, JS_ARRAY_TYPE); 1708 __ j(equal, &create_array); 1709 1710 // Ask the runtime to create the list (actually a FixedArray). 1711 __ bind(&create_runtime); 1712 { 1713 FrameScope scope(masm, StackFrame::INTERNAL); 1714 __ Push(edi); 1715 __ Push(edx); 1716 __ Push(eax); 1717 __ CallRuntime(Runtime::kCreateListFromArrayLike); 1718 __ Pop(edx); 1719 __ Pop(edi); 1720 __ mov(ebx, FieldOperand(eax, FixedArray::kLengthOffset)); 1721 __ SmiUntag(ebx); 1722 } 1723 __ jmp(&done_create); 1724 1725 // Try to create the list from an arguments object. 1726 __ bind(&create_arguments); 1727 __ mov(ebx, 1728 FieldOperand(eax, JSObject::kHeaderSize + 1729 Heap::kArgumentsLengthIndex * kPointerSize)); 1730 __ mov(ecx, FieldOperand(eax, JSObject::kElementsOffset)); 1731 __ cmp(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); 1732 __ j(not_equal, &create_runtime); 1733 __ SmiUntag(ebx); 1734 __ mov(eax, ecx); 1735 __ jmp(&done_create); 1736 1737 // Try to create the list from a JSArray object. 1738 __ bind(&create_array); 1739 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); 1740 __ DecodeField<Map::ElementsKindBits>(ecx); 1741 STATIC_ASSERT(FAST_SMI_ELEMENTS == 0); 1742 STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); 1743 STATIC_ASSERT(FAST_ELEMENTS == 2); 1744 __ cmp(ecx, Immediate(FAST_ELEMENTS)); 1745 __ j(above, &create_runtime); 1746 __ cmp(ecx, Immediate(FAST_HOLEY_SMI_ELEMENTS)); 1747 __ j(equal, &create_runtime); 1748 __ mov(ebx, FieldOperand(eax, JSArray::kLengthOffset)); 1749 __ SmiUntag(ebx); 1750 __ mov(eax, FieldOperand(eax, JSArray::kElementsOffset)); 1751 1752 __ bind(&done_create); 1753 } 1754 1755 // Check for stack overflow. 1756 { 1757 // Check the stack for overflow. We are not trying to catch interruptions 1758 // (i.e. debug break and preemption) here, so check the "real stack limit". 1759 Label done; 1760 ExternalReference real_stack_limit = 1761 ExternalReference::address_of_real_stack_limit(masm->isolate()); 1762 __ mov(ecx, Operand::StaticVariable(real_stack_limit)); 1763 // Make ecx the space we have left. The stack might already be overflowed 1764 // here which will cause ecx to become negative. 1765 __ neg(ecx); 1766 __ add(ecx, esp); 1767 __ sar(ecx, kPointerSizeLog2); 1768 // Check if the arguments will overflow the stack. 1769 __ cmp(ecx, ebx); 1770 __ j(greater, &done, Label::kNear); // Signed comparison. 1771 __ TailCallRuntime(Runtime::kThrowStackOverflow); 1772 __ bind(&done); 1773 } 1774 1775 // ----------- S t a t e ------------- 1776 // -- edi : target 1777 // -- eax : args (a FixedArray built from argumentsList) 1778 // -- ebx : len (number of elements to push from args) 1779 // -- edx : new.target (checked to be constructor or undefined) 1780 // -- esp[0] : return address. 1781 // -- esp[4] : thisArgument 1782 // ----------------------------------- 1783 1784 // Push arguments onto the stack (thisArgument is already on the stack). 1785 { 1786 __ movd(xmm0, edx); 1787 __ PopReturnAddressTo(edx); 1788 __ Move(ecx, Immediate(0)); 1789 Label done, loop; 1790 __ bind(&loop); 1791 __ cmp(ecx, ebx); 1792 __ j(equal, &done, Label::kNear); 1793 __ Push( 1794 FieldOperand(eax, ecx, times_pointer_size, FixedArray::kHeaderSize)); 1795 __ inc(ecx); 1796 __ jmp(&loop); 1797 __ bind(&done); 1798 __ PushReturnAddressFrom(edx); 1799 __ movd(edx, xmm0); 1800 __ Move(eax, ebx); 1801 } 1802 1803 // Dispatch to Call or Construct depending on whether new.target is undefined. 1804 { 1805 __ CompareRoot(edx, Heap::kUndefinedValueRootIndex); 1806 __ j(equal, masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); 1807 __ Jump(masm->isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET); 1808 } 1809} 1810 1811 1812// static 1813void Builtins::Generate_CallFunction(MacroAssembler* masm, 1814 ConvertReceiverMode mode) { 1815 // ----------- S t a t e ------------- 1816 // -- eax : the number of arguments (not including the receiver) 1817 // -- edi : the function to call (checked to be a JSFunction) 1818 // ----------------------------------- 1819 __ AssertFunction(edi); 1820 1821 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) 1822 // Check that the function is not a "classConstructor". 1823 Label class_constructor; 1824 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 1825 __ test_b(FieldOperand(edx, SharedFunctionInfo::kFunctionKindByteOffset), 1826 SharedFunctionInfo::kClassConstructorBitsWithinByte); 1827 __ j(not_zero, &class_constructor); 1828 1829 // Enter the context of the function; ToObject has to run in the function 1830 // context, and we also need to take the global proxy from the function 1831 // context in case of conversion. 1832 STATIC_ASSERT(SharedFunctionInfo::kNativeByteOffset == 1833 SharedFunctionInfo::kStrictModeByteOffset); 1834 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 1835 // We need to convert the receiver for non-native sloppy mode functions. 1836 Label done_convert; 1837 __ test_b(FieldOperand(edx, SharedFunctionInfo::kNativeByteOffset), 1838 (1 << SharedFunctionInfo::kNativeBitWithinByte) | 1839 (1 << SharedFunctionInfo::kStrictModeBitWithinByte)); 1840 __ j(not_zero, &done_convert); 1841 { 1842 // ----------- S t a t e ------------- 1843 // -- eax : the number of arguments (not including the receiver) 1844 // -- edx : the shared function info. 1845 // -- edi : the function to call (checked to be a JSFunction) 1846 // -- esi : the function context. 1847 // ----------------------------------- 1848 1849 if (mode == ConvertReceiverMode::kNullOrUndefined) { 1850 // Patch receiver to global proxy. 1851 __ LoadGlobalProxy(ecx); 1852 } else { 1853 Label convert_to_object, convert_receiver; 1854 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize)); 1855 __ JumpIfSmi(ecx, &convert_to_object, Label::kNear); 1856 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); 1857 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx); 1858 __ j(above_equal, &done_convert); 1859 if (mode != ConvertReceiverMode::kNotNullOrUndefined) { 1860 Label convert_global_proxy; 1861 __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex, 1862 &convert_global_proxy, Label::kNear); 1863 __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object, 1864 Label::kNear); 1865 __ bind(&convert_global_proxy); 1866 { 1867 // Patch receiver to global proxy. 1868 __ LoadGlobalProxy(ecx); 1869 } 1870 __ jmp(&convert_receiver); 1871 } 1872 __ bind(&convert_to_object); 1873 { 1874 // Convert receiver using ToObject. 1875 // TODO(bmeurer): Inline the allocation here to avoid building the frame 1876 // in the fast case? (fall back to AllocateInNewSpace?) 1877 FrameScope scope(masm, StackFrame::INTERNAL); 1878 __ SmiTag(eax); 1879 __ Push(eax); 1880 __ Push(edi); 1881 __ mov(eax, ecx); 1882 ToObjectStub stub(masm->isolate()); 1883 __ CallStub(&stub); 1884 __ mov(ecx, eax); 1885 __ Pop(edi); 1886 __ Pop(eax); 1887 __ SmiUntag(eax); 1888 } 1889 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 1890 __ bind(&convert_receiver); 1891 } 1892 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx); 1893 } 1894 __ bind(&done_convert); 1895 1896 // ----------- S t a t e ------------- 1897 // -- eax : the number of arguments (not including the receiver) 1898 // -- edx : the shared function info. 1899 // -- edi : the function to call (checked to be a JSFunction) 1900 // -- esi : the function context. 1901 // ----------------------------------- 1902 1903 __ mov(ebx, 1904 FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); 1905 __ SmiUntag(ebx); 1906 ParameterCount actual(eax); 1907 ParameterCount expected(ebx); 1908 __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION, 1909 CheckDebugStepCallWrapper()); 1910 // The function is a "classConstructor", need to raise an exception. 1911 __ bind(&class_constructor); 1912 { 1913 FrameScope frame(masm, StackFrame::INTERNAL); 1914 __ push(edi); 1915 __ CallRuntime(Runtime::kThrowConstructorNonCallableError); 1916 } 1917} 1918 1919 1920namespace { 1921 1922void Generate_PushBoundArguments(MacroAssembler* masm) { 1923 // ----------- S t a t e ------------- 1924 // -- eax : the number of arguments (not including the receiver) 1925 // -- edx : new.target (only in case of [[Construct]]) 1926 // -- edi : target (checked to be a JSBoundFunction) 1927 // ----------------------------------- 1928 1929 // Load [[BoundArguments]] into ecx and length of that into ebx. 1930 Label no_bound_arguments; 1931 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset)); 1932 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); 1933 __ SmiUntag(ebx); 1934 __ test(ebx, ebx); 1935 __ j(zero, &no_bound_arguments); 1936 { 1937 // ----------- S t a t e ------------- 1938 // -- eax : the number of arguments (not including the receiver) 1939 // -- edx : new.target (only in case of [[Construct]]) 1940 // -- edi : target (checked to be a JSBoundFunction) 1941 // -- ecx : the [[BoundArguments]] (implemented as FixedArray) 1942 // -- ebx : the number of [[BoundArguments]] 1943 // ----------------------------------- 1944 1945 // Reserve stack space for the [[BoundArguments]]. 1946 { 1947 Label done; 1948 __ lea(ecx, Operand(ebx, times_pointer_size, 0)); 1949 __ sub(esp, ecx); 1950 // Check the stack for overflow. We are not trying to catch interruptions 1951 // (i.e. debug break and preemption) here, so check the "real stack 1952 // limit". 1953 __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex); 1954 __ j(greater, &done, Label::kNear); // Signed comparison. 1955 // Restore the stack pointer. 1956 __ lea(esp, Operand(esp, ebx, times_pointer_size, 0)); 1957 { 1958 FrameScope scope(masm, StackFrame::MANUAL); 1959 __ EnterFrame(StackFrame::INTERNAL); 1960 __ CallRuntime(Runtime::kThrowStackOverflow); 1961 } 1962 __ bind(&done); 1963 } 1964 1965 // Adjust effective number of arguments to include return address. 1966 __ inc(eax); 1967 1968 // Relocate arguments and return address down the stack. 1969 { 1970 Label loop; 1971 __ Set(ecx, 0); 1972 __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0)); 1973 __ bind(&loop); 1974 __ movd(xmm0, Operand(ebx, ecx, times_pointer_size, 0)); 1975 __ movd(Operand(esp, ecx, times_pointer_size, 0), xmm0); 1976 __ inc(ecx); 1977 __ cmp(ecx, eax); 1978 __ j(less, &loop); 1979 } 1980 1981 // Copy [[BoundArguments]] to the stack (below the arguments). 1982 { 1983 Label loop; 1984 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset)); 1985 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); 1986 __ SmiUntag(ebx); 1987 __ bind(&loop); 1988 __ dec(ebx); 1989 __ movd(xmm0, FieldOperand(ecx, ebx, times_pointer_size, 1990 FixedArray::kHeaderSize)); 1991 __ movd(Operand(esp, eax, times_pointer_size, 0), xmm0); 1992 __ lea(eax, Operand(eax, 1)); 1993 __ j(greater, &loop); 1994 } 1995 1996 // Adjust effective number of arguments (eax contains the number of 1997 // arguments from the call plus return address plus the number of 1998 // [[BoundArguments]]), so we need to subtract one for the return address. 1999 __ dec(eax); 2000 } 2001 __ bind(&no_bound_arguments); 2002} 2003 2004} // namespace 2005 2006 2007// static 2008void Builtins::Generate_CallBoundFunction(MacroAssembler* masm) { 2009 // ----------- S t a t e ------------- 2010 // -- eax : the number of arguments (not including the receiver) 2011 // -- edi : the function to call (checked to be a JSBoundFunction) 2012 // ----------------------------------- 2013 __ AssertBoundFunction(edi); 2014 2015 // Patch the receiver to [[BoundThis]]. 2016 __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset)); 2017 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx); 2018 2019 // Push the [[BoundArguments]] onto the stack. 2020 Generate_PushBoundArguments(masm); 2021 2022 // Call the [[BoundTargetFunction]] via the Call builtin. 2023 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); 2024 __ mov(ecx, Operand::StaticVariable(ExternalReference( 2025 Builtins::kCall_ReceiverIsAny, masm->isolate()))); 2026 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); 2027 __ jmp(ecx); 2028} 2029 2030 2031// static 2032void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { 2033 // ----------- S t a t e ------------- 2034 // -- eax : the number of arguments (not including the receiver) 2035 // -- edi : the target to call (can be any Object). 2036 // ----------------------------------- 2037 2038 Label non_callable, non_function, non_smi; 2039 __ JumpIfSmi(edi, &non_callable); 2040 __ bind(&non_smi); 2041 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 2042 __ j(equal, masm->isolate()->builtins()->CallFunction(mode), 2043 RelocInfo::CODE_TARGET); 2044 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE); 2045 __ j(equal, masm->isolate()->builtins()->CallBoundFunction(), 2046 RelocInfo::CODE_TARGET); 2047 __ CmpInstanceType(ecx, JS_PROXY_TYPE); 2048 __ j(not_equal, &non_function); 2049 2050 // 1. Runtime fallback for Proxy [[Call]]. 2051 __ PopReturnAddressTo(ecx); 2052 __ Push(edi); 2053 __ PushReturnAddressFrom(ecx); 2054 // Increase the arguments size to include the pushed function and the 2055 // existing receiver on the stack. 2056 __ add(eax, Immediate(2)); 2057 // Tail-call to the runtime. 2058 __ JumpToExternalReference( 2059 ExternalReference(Runtime::kJSProxyCall, masm->isolate())); 2060 2061 // 2. Call to something else, which might have a [[Call]] internal method (if 2062 // not we raise an exception). 2063 __ bind(&non_function); 2064 // Check if target has a [[Call]] internal method. 2065 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsCallable); 2066 __ j(zero, &non_callable, Label::kNear); 2067 // Overwrite the original receiver with the (original) target. 2068 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi); 2069 // Let the "call_as_function_delegate" take care of the rest. 2070 __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi); 2071 __ Jump(masm->isolate()->builtins()->CallFunction( 2072 ConvertReceiverMode::kNotNullOrUndefined), 2073 RelocInfo::CODE_TARGET); 2074 2075 // 3. Call to something that is not callable. 2076 __ bind(&non_callable); 2077 { 2078 FrameScope scope(masm, StackFrame::INTERNAL); 2079 __ Push(edi); 2080 __ CallRuntime(Runtime::kThrowCalledNonCallable); 2081 } 2082} 2083 2084 2085// static 2086void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { 2087 // ----------- S t a t e ------------- 2088 // -- eax : the number of arguments (not including the receiver) 2089 // -- edx : the new target (checked to be a constructor) 2090 // -- edi : the constructor to call (checked to be a JSFunction) 2091 // ----------------------------------- 2092 __ AssertFunction(edi); 2093 2094 // Calling convention for function specific ConstructStubs require 2095 // ebx to contain either an AllocationSite or undefined. 2096 __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex); 2097 2098 // Tail call to the function-specific construct stub (still in the caller 2099 // context at this point). 2100 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 2101 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kConstructStubOffset)); 2102 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); 2103 __ jmp(ecx); 2104} 2105 2106 2107// static 2108void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) { 2109 // ----------- S t a t e ------------- 2110 // -- eax : the number of arguments (not including the receiver) 2111 // -- edx : the new target (checked to be a constructor) 2112 // -- edi : the constructor to call (checked to be a JSBoundFunction) 2113 // ----------------------------------- 2114 __ AssertBoundFunction(edi); 2115 2116 // Push the [[BoundArguments]] onto the stack. 2117 Generate_PushBoundArguments(masm); 2118 2119 // Patch new.target to [[BoundTargetFunction]] if new.target equals target. 2120 { 2121 Label done; 2122 __ cmp(edi, edx); 2123 __ j(not_equal, &done, Label::kNear); 2124 __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); 2125 __ bind(&done); 2126 } 2127 2128 // Construct the [[BoundTargetFunction]] via the Construct builtin. 2129 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); 2130 __ mov(ecx, Operand::StaticVariable( 2131 ExternalReference(Builtins::kConstruct, masm->isolate()))); 2132 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); 2133 __ jmp(ecx); 2134} 2135 2136 2137// static 2138void Builtins::Generate_ConstructProxy(MacroAssembler* masm) { 2139 // ----------- S t a t e ------------- 2140 // -- eax : the number of arguments (not including the receiver) 2141 // -- edi : the constructor to call (checked to be a JSProxy) 2142 // -- edx : the new target (either the same as the constructor or 2143 // the JSFunction on which new was invoked initially) 2144 // ----------------------------------- 2145 2146 // Call into the Runtime for Proxy [[Construct]]. 2147 __ PopReturnAddressTo(ecx); 2148 __ Push(edi); 2149 __ Push(edx); 2150 __ PushReturnAddressFrom(ecx); 2151 // Include the pushed new_target, constructor and the receiver. 2152 __ add(eax, Immediate(3)); 2153 // Tail-call to the runtime. 2154 __ JumpToExternalReference( 2155 ExternalReference(Runtime::kJSProxyConstruct, masm->isolate())); 2156} 2157 2158 2159// static 2160void Builtins::Generate_Construct(MacroAssembler* masm) { 2161 // ----------- S t a t e ------------- 2162 // -- eax : the number of arguments (not including the receiver) 2163 // -- edx : the new target (either the same as the constructor or 2164 // the JSFunction on which new was invoked initially) 2165 // -- edi : the constructor to call (can be any Object) 2166 // ----------------------------------- 2167 2168 // Check if target is a Smi. 2169 Label non_constructor; 2170 __ JumpIfSmi(edi, &non_constructor, Label::kNear); 2171 2172 // Dispatch based on instance type. 2173 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 2174 __ j(equal, masm->isolate()->builtins()->ConstructFunction(), 2175 RelocInfo::CODE_TARGET); 2176 2177 // Check if target has a [[Construct]] internal method. 2178 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 1 << Map::kIsConstructor); 2179 __ j(zero, &non_constructor, Label::kNear); 2180 2181 // Only dispatch to bound functions after checking whether they are 2182 // constructors. 2183 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE); 2184 __ j(equal, masm->isolate()->builtins()->ConstructBoundFunction(), 2185 RelocInfo::CODE_TARGET); 2186 2187 // Only dispatch to proxies after checking whether they are constructors. 2188 __ CmpInstanceType(ecx, JS_PROXY_TYPE); 2189 __ j(equal, masm->isolate()->builtins()->ConstructProxy(), 2190 RelocInfo::CODE_TARGET); 2191 2192 // Called Construct on an exotic Object with a [[Construct]] internal method. 2193 { 2194 // Overwrite the original receiver with the (original) target. 2195 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi); 2196 // Let the "call_as_constructor_delegate" take care of the rest. 2197 __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi); 2198 __ Jump(masm->isolate()->builtins()->CallFunction(), 2199 RelocInfo::CODE_TARGET); 2200 } 2201 2202 // Called Construct on an Object that doesn't have a [[Construct]] internal 2203 // method. 2204 __ bind(&non_constructor); 2205 __ Jump(masm->isolate()->builtins()->ConstructedNonConstructable(), 2206 RelocInfo::CODE_TARGET); 2207} 2208 2209 2210void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { 2211 // ----------- S t a t e ------------- 2212 // -- eax : actual number of arguments 2213 // -- ebx : expected number of arguments 2214 // -- edx : new target (passed through to callee) 2215 // -- edi : function (passed through to callee) 2216 // ----------------------------------- 2217 2218 Label invoke, dont_adapt_arguments, stack_overflow; 2219 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1); 2220 2221 Label enough, too_few; 2222 __ cmp(eax, ebx); 2223 __ j(less, &too_few); 2224 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); 2225 __ j(equal, &dont_adapt_arguments); 2226 2227 { // Enough parameters: Actual >= expected. 2228 __ bind(&enough); 2229 EnterArgumentsAdaptorFrame(masm); 2230 ArgumentsAdaptorStackCheck(masm, &stack_overflow); 2231 2232 // Copy receiver and all expected arguments. 2233 const int offset = StandardFrameConstants::kCallerSPOffset; 2234 __ lea(edi, Operand(ebp, eax, times_4, offset)); 2235 __ mov(eax, -1); // account for receiver 2236 2237 Label copy; 2238 __ bind(©); 2239 __ inc(eax); 2240 __ push(Operand(edi, 0)); 2241 __ sub(edi, Immediate(kPointerSize)); 2242 __ cmp(eax, ebx); 2243 __ j(less, ©); 2244 // eax now contains the expected number of arguments. 2245 __ jmp(&invoke); 2246 } 2247 2248 { // Too few parameters: Actual < expected. 2249 __ bind(&too_few); 2250 2251 // If the function is strong we need to throw an error. 2252 Label no_strong_error; 2253 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 2254 __ test_b(FieldOperand(ecx, SharedFunctionInfo::kStrongModeByteOffset), 2255 1 << SharedFunctionInfo::kStrongModeBitWithinByte); 2256 __ j(equal, &no_strong_error, Label::kNear); 2257 2258 // What we really care about is the required number of arguments. 2259 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kLengthOffset)); 2260 __ SmiUntag(ecx); 2261 __ cmp(eax, ecx); 2262 __ j(greater_equal, &no_strong_error, Label::kNear); 2263 2264 { 2265 FrameScope frame(masm, StackFrame::MANUAL); 2266 EnterArgumentsAdaptorFrame(masm); 2267 __ CallRuntime(Runtime::kThrowStrongModeTooFewArguments); 2268 } 2269 2270 __ bind(&no_strong_error); 2271 EnterArgumentsAdaptorFrame(masm); 2272 ArgumentsAdaptorStackCheck(masm, &stack_overflow); 2273 2274 // Remember expected arguments in ecx. 2275 __ mov(ecx, ebx); 2276 2277 // Copy receiver and all actual arguments. 2278 const int offset = StandardFrameConstants::kCallerSPOffset; 2279 __ lea(edi, Operand(ebp, eax, times_4, offset)); 2280 // ebx = expected - actual. 2281 __ sub(ebx, eax); 2282 // eax = -actual - 1 2283 __ neg(eax); 2284 __ sub(eax, Immediate(1)); 2285 2286 Label copy; 2287 __ bind(©); 2288 __ inc(eax); 2289 __ push(Operand(edi, 0)); 2290 __ sub(edi, Immediate(kPointerSize)); 2291 __ test(eax, eax); 2292 __ j(not_zero, ©); 2293 2294 // Fill remaining expected arguments with undefined values. 2295 Label fill; 2296 __ bind(&fill); 2297 __ inc(eax); 2298 __ push(Immediate(masm->isolate()->factory()->undefined_value())); 2299 __ cmp(eax, ebx); 2300 __ j(less, &fill); 2301 2302 // Restore expected arguments. 2303 __ mov(eax, ecx); 2304 } 2305 2306 // Call the entry point. 2307 __ bind(&invoke); 2308 // Restore function pointer. 2309 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 2310 // eax : expected number of arguments 2311 // edx : new target (passed through to callee) 2312 // edi : function (passed through to callee) 2313 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset)); 2314 __ call(ecx); 2315 2316 // Store offset of return address for deoptimizer. 2317 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset()); 2318 2319 // Leave frame and return. 2320 LeaveArgumentsAdaptorFrame(masm); 2321 __ ret(0); 2322 2323 // ------------------------------------------- 2324 // Dont adapt arguments. 2325 // ------------------------------------------- 2326 __ bind(&dont_adapt_arguments); 2327 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeEntryOffset)); 2328 __ jmp(ecx); 2329 2330 __ bind(&stack_overflow); 2331 { 2332 FrameScope frame(masm, StackFrame::MANUAL); 2333 __ CallRuntime(Runtime::kThrowStackOverflow); 2334 __ int3(); 2335 } 2336} 2337 2338 2339static void CompatibleReceiverCheck(MacroAssembler* masm, Register receiver, 2340 Register function_template_info, 2341 Register scratch0, Register scratch1, 2342 Label* receiver_check_failed) { 2343 // If there is no signature, return the holder. 2344 __ CompareRoot(FieldOperand(function_template_info, 2345 FunctionTemplateInfo::kSignatureOffset), 2346 Heap::kUndefinedValueRootIndex); 2347 Label receiver_check_passed; 2348 __ j(equal, &receiver_check_passed, Label::kNear); 2349 2350 // Walk the prototype chain. 2351 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset)); 2352 Label prototype_loop_start; 2353 __ bind(&prototype_loop_start); 2354 2355 // Get the constructor, if any. 2356 __ GetMapConstructor(scratch0, scratch0, scratch1); 2357 __ CmpInstanceType(scratch1, JS_FUNCTION_TYPE); 2358 Label next_prototype; 2359 __ j(not_equal, &next_prototype, Label::kNear); 2360 2361 // Get the constructor's signature. 2362 __ mov(scratch0, 2363 FieldOperand(scratch0, JSFunction::kSharedFunctionInfoOffset)); 2364 __ mov(scratch0, 2365 FieldOperand(scratch0, SharedFunctionInfo::kFunctionDataOffset)); 2366 2367 // Loop through the chain of inheriting function templates. 2368 Label function_template_loop; 2369 __ bind(&function_template_loop); 2370 2371 // If the signatures match, we have a compatible receiver. 2372 __ cmp(scratch0, FieldOperand(function_template_info, 2373 FunctionTemplateInfo::kSignatureOffset)); 2374 __ j(equal, &receiver_check_passed, Label::kNear); 2375 2376 // If the current type is not a FunctionTemplateInfo, load the next prototype 2377 // in the chain. 2378 __ JumpIfSmi(scratch0, &next_prototype, Label::kNear); 2379 __ CmpObjectType(scratch0, FUNCTION_TEMPLATE_INFO_TYPE, scratch1); 2380 __ j(not_equal, &next_prototype, Label::kNear); 2381 2382 // Otherwise load the parent function template and iterate. 2383 __ mov(scratch0, 2384 FieldOperand(scratch0, FunctionTemplateInfo::kParentTemplateOffset)); 2385 __ jmp(&function_template_loop, Label::kNear); 2386 2387 // Load the next prototype. 2388 __ bind(&next_prototype); 2389 __ mov(receiver, FieldOperand(receiver, HeapObject::kMapOffset)); 2390 __ mov(receiver, FieldOperand(receiver, Map::kPrototypeOffset)); 2391 // End if the prototype is null or not hidden. 2392 __ CompareRoot(receiver, Heap::kNullValueRootIndex); 2393 __ j(equal, receiver_check_failed); 2394 __ mov(scratch0, FieldOperand(receiver, HeapObject::kMapOffset)); 2395 __ test(FieldOperand(scratch0, Map::kBitField3Offset), 2396 Immediate(Map::IsHiddenPrototype::kMask)); 2397 __ j(zero, receiver_check_failed); 2398 // Iterate. 2399 __ jmp(&prototype_loop_start, Label::kNear); 2400 2401 __ bind(&receiver_check_passed); 2402} 2403 2404 2405void Builtins::Generate_HandleFastApiCall(MacroAssembler* masm) { 2406 // ----------- S t a t e ------------- 2407 // -- eax : number of arguments (not including the receiver) 2408 // -- edi : callee 2409 // -- esi : context 2410 // -- esp[0] : return address 2411 // -- esp[4] : last argument 2412 // -- ... 2413 // -- esp[eax * 4] : first argument 2414 // -- esp[(eax + 1) * 4] : receiver 2415 // ----------------------------------- 2416 2417 // Load the FunctionTemplateInfo. 2418 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 2419 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset)); 2420 2421 // Do the compatible receiver check. 2422 Label receiver_check_failed; 2423 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPCOnStackSize)); 2424 __ Push(eax); 2425 CompatibleReceiverCheck(masm, ecx, ebx, edx, eax, &receiver_check_failed); 2426 __ Pop(eax); 2427 // Get the callback offset from the FunctionTemplateInfo, and jump to the 2428 // beginning of the code. 2429 __ mov(edx, FieldOperand(ebx, FunctionTemplateInfo::kCallCodeOffset)); 2430 __ mov(edx, FieldOperand(edx, CallHandlerInfo::kFastHandlerOffset)); 2431 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag)); 2432 __ jmp(edx); 2433 2434 // Compatible receiver check failed: pop return address, arguments and 2435 // receiver and throw an Illegal Invocation exception. 2436 __ bind(&receiver_check_failed); 2437 __ Pop(eax); 2438 __ PopReturnAddressTo(ebx); 2439 __ lea(eax, Operand(eax, times_pointer_size, 1 * kPointerSize)); 2440 __ add(esp, eax); 2441 __ PushReturnAddressFrom(ebx); 2442 { 2443 FrameScope scope(masm, StackFrame::INTERNAL); 2444 __ TailCallRuntime(Runtime::kThrowIllegalInvocation); 2445 } 2446} 2447 2448 2449void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) { 2450 // Lookup the function in the JavaScript frame. 2451 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 2452 { 2453 FrameScope scope(masm, StackFrame::INTERNAL); 2454 // Pass function as argument. 2455 __ push(eax); 2456 __ CallRuntime(Runtime::kCompileForOnStackReplacement); 2457 } 2458 2459 Label skip; 2460 // If the code object is null, just return to the unoptimized code. 2461 __ cmp(eax, Immediate(0)); 2462 __ j(not_equal, &skip, Label::kNear); 2463 __ ret(0); 2464 2465 __ bind(&skip); 2466 2467 // Load deoptimization data from the code object. 2468 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag)); 2469 2470 // Load the OSR entrypoint offset from the deoptimization data. 2471 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt( 2472 DeoptimizationInputData::kOsrPcOffsetIndex) - kHeapObjectTag)); 2473 __ SmiUntag(ebx); 2474 2475 // Compute the target address = code_obj + header_size + osr_offset 2476 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag)); 2477 2478 // Overwrite the return address on the stack. 2479 __ mov(Operand(esp, 0), eax); 2480 2481 // And "return" to the OSR entry point of the function. 2482 __ ret(0); 2483} 2484 2485 2486void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) { 2487 // We check the stack limit as indicator that recompilation might be done. 2488 Label ok; 2489 ExternalReference stack_limit = 2490 ExternalReference::address_of_stack_limit(masm->isolate()); 2491 __ cmp(esp, Operand::StaticVariable(stack_limit)); 2492 __ j(above_equal, &ok, Label::kNear); 2493 { 2494 FrameScope scope(masm, StackFrame::INTERNAL); 2495 __ CallRuntime(Runtime::kStackGuard); 2496 } 2497 __ jmp(masm->isolate()->builtins()->OnStackReplacement(), 2498 RelocInfo::CODE_TARGET); 2499 2500 __ bind(&ok); 2501 __ ret(0); 2502} 2503 2504#undef __ 2505} // namespace internal 2506} // namespace v8 2507 2508#endif // V8_TARGET_ARCH_IA32 2509