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/base/adapters.h" 8 #include "src/code-factory.h" 9 #include "src/debug/debug.h" 10 #include "src/deoptimizer.h" 11 #include "src/frame-constants.h" 12 #include "src/frames.h" 13 #include "src/objects-inl.h" 14 #include "src/objects/js-generator.h" 15 #include "src/wasm/wasm-linkage.h" 16 #include "src/wasm/wasm-objects.h" 17 18 namespace v8 { 19 namespace internal { 20 21 #define __ ACCESS_MASM(masm) 22 23 void Builtins::Generate_Adaptor(MacroAssembler* masm, Address address, 24 ExitFrameType exit_frame_type) { 25 __ mov(kJavaScriptCallExtraArg1Register, 26 Immediate(ExternalReference::Create(address))); 27 if (exit_frame_type == BUILTIN_EXIT) { 28 __ Jump(BUILTIN_CODE(masm->isolate(), AdaptorWithBuiltinExitFrame), 29 RelocInfo::CODE_TARGET); 30 } else { 31 DCHECK(exit_frame_type == EXIT); 32 __ Jump(BUILTIN_CODE(masm->isolate(), AdaptorWithExitFrame), 33 RelocInfo::CODE_TARGET); 34 } 35 } 36 37 static void GenerateTailCallToReturnedCode(MacroAssembler* masm, 38 Runtime::FunctionId function_id) { 39 // ----------- S t a t e ------------- 40 // -- eax : argument count (preserved for callee) 41 // -- edx : new target (preserved for callee) 42 // -- edi : target function (preserved for callee) 43 // ----------------------------------- 44 { 45 FrameScope scope(masm, StackFrame::INTERNAL); 46 // Push the number of arguments to the callee. 47 __ SmiTag(eax); 48 __ push(eax); 49 // Push a copy of the target function and the new target. 50 __ push(edi); 51 __ push(edx); 52 // Function is also the parameter to the runtime call. 53 __ push(edi); 54 55 __ CallRuntime(function_id, 1); 56 __ mov(ecx, eax); 57 58 // Restore target function and new target. 59 __ pop(edx); 60 __ pop(edi); 61 __ pop(eax); 62 __ SmiUntag(eax); 63 } 64 65 static_assert(kJavaScriptCallCodeStartRegister == ecx, "ABI mismatch"); 66 __ lea(ecx, FieldOperand(ecx, Code::kHeaderSize)); 67 __ jmp(ecx); 68 } 69 70 namespace { 71 72 void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { 73 // ----------- S t a t e ------------- 74 // -- eax: number of arguments 75 // -- edi: constructor function 76 // -- edx: new target 77 // -- esi: context 78 // ----------------------------------- 79 80 // Enter a construct frame. 81 { 82 FrameScope scope(masm, StackFrame::CONSTRUCT); 83 84 // Preserve the incoming parameters on the stack. 85 __ SmiTag(eax); 86 __ push(esi); 87 __ push(eax); 88 __ SmiUntag(eax); 89 90 // The receiver for the builtin/api call. 91 __ PushRoot(Heap::kTheHoleValueRootIndex); 92 93 // Set up pointer to last argument. 94 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); 95 96 // Copy arguments and receiver to the expression stack. 97 Label loop, entry; 98 __ mov(ecx, eax); 99 // ----------- S t a t e ------------- 100 // -- eax: number of arguments (untagged) 101 // -- edi: constructor function 102 // -- edx: new target 103 // -- ebx: pointer to last argument 104 // -- ecx: counter 105 // -- sp[0*kPointerSize]: the hole (receiver) 106 // -- sp[1*kPointerSize]: number of arguments (tagged) 107 // -- sp[2*kPointerSize]: context 108 // ----------------------------------- 109 __ jmp(&entry); 110 __ bind(&loop); 111 __ push(Operand(ebx, ecx, times_4, 0)); 112 __ bind(&entry); 113 __ dec(ecx); 114 __ j(greater_equal, &loop); 115 116 // Call the function. 117 // eax: number of arguments (untagged) 118 // edi: constructor function 119 // edx: new target 120 ParameterCount actual(eax); 121 __ InvokeFunction(edi, edx, actual, CALL_FUNCTION); 122 123 // Restore context from the frame. 124 __ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset)); 125 // Restore smi-tagged arguments count from the frame. 126 __ mov(ebx, Operand(ebp, ConstructFrameConstants::kLengthOffset)); 127 // Leave construct frame. 128 } 129 130 // Remove caller arguments from the stack and return. 131 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 132 __ pop(ecx); 133 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver 134 __ push(ecx); 135 __ ret(0); 136 } 137 138 } // namespace 139 140 // The construct stub for ES5 constructor functions and ES6 class constructors. 141 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { 142 // ----------- S t a t e ------------- 143 // -- eax: number of arguments (untagged) 144 // -- edi: constructor function 145 // -- edx: new target 146 // -- esi: context 147 // -- sp[...]: constructor arguments 148 // ----------------------------------- 149 150 // Enter a construct frame. 151 { 152 FrameScope scope(masm, StackFrame::CONSTRUCT); 153 Label post_instantiation_deopt_entry, not_create_implicit_receiver; 154 155 // Preserve the incoming parameters on the stack. 156 __ mov(ecx, eax); 157 __ SmiTag(ecx); 158 __ Push(esi); 159 __ Push(ecx); 160 __ Push(edi); 161 __ PushRoot(Heap::kTheHoleValueRootIndex); 162 __ Push(edx); 163 164 // ----------- S t a t e ------------- 165 // -- sp[0*kPointerSize]: new target 166 // -- sp[1*kPointerSize]: padding 167 // -- edi and sp[2*kPointerSize]: constructor function 168 // -- sp[3*kPointerSize]: argument count 169 // -- sp[4*kPointerSize]: context 170 // ----------------------------------- 171 172 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 173 __ test(FieldOperand(ebx, SharedFunctionInfo::kFlagsOffset), 174 Immediate(SharedFunctionInfo::IsDerivedConstructorBit::kMask)); 175 __ j(not_zero, ¬_create_implicit_receiver); 176 177 // If not derived class constructor: Allocate the new receiver object. 178 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); 179 __ Call(BUILTIN_CODE(masm->isolate(), FastNewObject), 180 RelocInfo::CODE_TARGET); 181 __ jmp(&post_instantiation_deopt_entry, Label::kNear); 182 183 // Else: use TheHoleValue as receiver for constructor call 184 __ bind(¬_create_implicit_receiver); 185 __ LoadRoot(eax, Heap::kTheHoleValueRootIndex); 186 187 // ----------- S t a t e ------------- 188 // -- eax: implicit receiver 189 // -- Slot 4 / sp[0*kPointerSize]: new target 190 // -- Slot 3 / sp[1*kPointerSize]: padding 191 // -- Slot 2 / sp[2*kPointerSize]: constructor function 192 // -- Slot 1 / sp[3*kPointerSize]: number of arguments (tagged) 193 // -- Slot 0 / sp[4*kPointerSize]: context 194 // ----------------------------------- 195 // Deoptimizer enters here. 196 masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset( 197 masm->pc_offset()); 198 __ bind(&post_instantiation_deopt_entry); 199 200 // Restore new target. 201 __ Pop(edx); 202 203 // Push the allocated receiver to the stack. We need two copies 204 // because we may have to return the original one and the calling 205 // conventions dictate that the called function pops the receiver. 206 __ Push(eax); 207 __ Push(eax); 208 209 // ----------- S t a t e ------------- 210 // -- edx: new target 211 // -- sp[0*kPointerSize]: implicit receiver 212 // -- sp[1*kPointerSize]: implicit receiver 213 // -- sp[2*kPointerSize]: padding 214 // -- sp[3*kPointerSize]: constructor function 215 // -- sp[4*kPointerSize]: number of arguments (tagged) 216 // -- sp[5*kPointerSize]: context 217 // ----------------------------------- 218 219 // Restore constructor function and argument count. 220 __ mov(edi, Operand(ebp, ConstructFrameConstants::kConstructorOffset)); 221 __ mov(eax, Operand(ebp, ConstructFrameConstants::kLengthOffset)); 222 __ SmiUntag(eax); 223 224 // Set up pointer to last argument. 225 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); 226 227 // Copy arguments and receiver to the expression stack. 228 Label loop, entry; 229 __ mov(ecx, eax); 230 // ----------- S t a t e ------------- 231 // -- eax: number of arguments (untagged) 232 // -- edx: new target 233 // -- ebx: pointer to last argument 234 // -- ecx: counter (tagged) 235 // -- sp[0*kPointerSize]: implicit receiver 236 // -- sp[1*kPointerSize]: implicit receiver 237 // -- sp[2*kPointerSize]: padding 238 // -- edi and sp[3*kPointerSize]: constructor function 239 // -- sp[4*kPointerSize]: number of arguments (tagged) 240 // -- sp[5*kPointerSize]: context 241 // ----------------------------------- 242 __ jmp(&entry, Label::kNear); 243 __ bind(&loop); 244 __ Push(Operand(ebx, ecx, times_pointer_size, 0)); 245 __ bind(&entry); 246 __ dec(ecx); 247 __ j(greater_equal, &loop); 248 249 // Call the function. 250 ParameterCount actual(eax); 251 __ InvokeFunction(edi, edx, actual, CALL_FUNCTION); 252 253 // ----------- S t a t e ------------- 254 // -- eax: constructor result 255 // -- sp[0*kPointerSize]: implicit receiver 256 // -- sp[1*kPointerSize]: padding 257 // -- sp[2*kPointerSize]: constructor function 258 // -- sp[3*kPointerSize]: number of arguments 259 // -- sp[4*kPointerSize]: context 260 // ----------------------------------- 261 262 // Store offset of return address for deoptimizer. 263 masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset( 264 masm->pc_offset()); 265 266 // Restore context from the frame. 267 __ mov(esi, Operand(ebp, ConstructFrameConstants::kContextOffset)); 268 269 // If the result is an object (in the ECMA sense), we should get rid 270 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 271 // on page 74. 272 Label use_receiver, do_throw, leave_frame; 273 274 // If the result is undefined, we jump out to using the implicit receiver. 275 __ JumpIfRoot(eax, Heap::kUndefinedValueRootIndex, &use_receiver, 276 Label::kNear); 277 278 // Otherwise we do a smi check and fall through to check if the return value 279 // is a valid receiver. 280 281 // If the result is a smi, it is *not* an object in the ECMA sense. 282 __ JumpIfSmi(eax, &use_receiver, Label::kNear); 283 284 // If the type of the result (stored in its map) is less than 285 // FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense. 286 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); 287 __ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx); 288 __ j(above_equal, &leave_frame, Label::kNear); 289 __ jmp(&use_receiver, Label::kNear); 290 291 __ bind(&do_throw); 292 __ CallRuntime(Runtime::kThrowConstructorReturnedNonObject); 293 294 // Throw away the result of the constructor invocation and use the 295 // on-stack receiver as the result. 296 __ bind(&use_receiver); 297 __ mov(eax, Operand(esp, 0 * kPointerSize)); 298 __ JumpIfRoot(eax, Heap::kTheHoleValueRootIndex, &do_throw); 299 300 __ bind(&leave_frame); 301 // Restore smi-tagged arguments count from the frame. 302 __ mov(ebx, Operand(ebp, ConstructFrameConstants::kLengthOffset)); 303 // Leave construct frame. 304 } 305 // Remove caller arguments from the stack and return. 306 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 307 __ pop(ecx); 308 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver 309 __ push(ecx); 310 __ ret(0); 311 } 312 313 void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) { 314 Generate_JSBuiltinsConstructStubHelper(masm); 315 } 316 317 void Builtins::Generate_ConstructedNonConstructable(MacroAssembler* masm) { 318 FrameScope scope(masm, StackFrame::INTERNAL); 319 __ push(edi); 320 __ CallRuntime(Runtime::kThrowConstructedNonConstructable); 321 } 322 323 static void Generate_StackOverflowCheck(MacroAssembler* masm, Register num_args, 324 Register scratch1, Register scratch2, 325 Label* stack_overflow, 326 bool include_receiver = false) { 327 // Check the stack for overflow. We are not trying to catch 328 // interruptions (e.g. debug break and preemption) here, so the "real stack 329 // limit" is checked. 330 ExternalReference real_stack_limit = 331 ExternalReference::address_of_real_stack_limit(masm->isolate()); 332 __ mov(scratch1, __ StaticVariable(real_stack_limit)); 333 // Make scratch2 the space we have left. The stack might already be overflowed 334 // here which will cause scratch2 to become negative. 335 __ mov(scratch2, esp); 336 __ sub(scratch2, scratch1); 337 // Make scratch1 the space we need for the array when it is unrolled onto the 338 // stack. 339 __ mov(scratch1, num_args); 340 if (include_receiver) { 341 __ add(scratch1, Immediate(1)); 342 } 343 __ shl(scratch1, kPointerSizeLog2); 344 // Check if the arguments will overflow the stack. 345 __ cmp(scratch2, scratch1); 346 __ j(less_equal, stack_overflow); // Signed comparison. 347 } 348 349 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, 350 bool is_construct) { 351 ProfileEntryHookStub::MaybeCallEntryHook(masm); 352 353 { 354 FrameScope scope(masm, StackFrame::INTERNAL); 355 356 // Setup the context (we need to use the caller context from the isolate). 357 ExternalReference context_address = ExternalReference::Create( 358 IsolateAddressId::kContextAddress, masm->isolate()); 359 __ mov(esi, __ StaticVariable(context_address)); 360 361 // Load the previous frame pointer (ebx) to access C arguments 362 __ mov(ebx, Operand(ebp, 0)); 363 364 // Push the function and the receiver onto the stack. 365 __ push(Operand(ebx, EntryFrameConstants::kFunctionArgOffset)); 366 __ push(Operand(ebx, EntryFrameConstants::kReceiverArgOffset)); 367 368 // Load the number of arguments and setup pointer to the arguments. 369 __ mov(eax, Operand(ebx, EntryFrameConstants::kArgcOffset)); 370 __ mov(ebx, Operand(ebx, EntryFrameConstants::kArgvOffset)); 371 372 // Check if we have enough stack space to push all arguments. 373 // Argument count in eax. Clobbers ecx and edx. 374 Label enough_stack_space, stack_overflow; 375 Generate_StackOverflowCheck(masm, eax, ecx, edx, &stack_overflow); 376 __ jmp(&enough_stack_space); 377 378 __ bind(&stack_overflow); 379 __ CallRuntime(Runtime::kThrowStackOverflow); 380 // This should be unreachable. 381 __ int3(); 382 383 __ bind(&enough_stack_space); 384 385 // Copy arguments to the stack in a loop. 386 Label loop, entry; 387 __ Move(ecx, Immediate(0)); 388 __ jmp(&entry, Label::kNear); 389 __ bind(&loop); 390 __ mov(edx, Operand(ebx, ecx, times_4, 0)); // push parameter from argv 391 __ push(Operand(edx, 0)); // dereference handle 392 __ inc(ecx); 393 __ bind(&entry); 394 __ cmp(ecx, eax); 395 __ j(not_equal, &loop); 396 397 // Load the previous frame pointer (ebx) to access C arguments 398 __ mov(ebx, Operand(ebp, 0)); 399 400 // Get the new.target and function from the frame. 401 __ mov(edx, Operand(ebx, EntryFrameConstants::kNewTargetArgOffset)); 402 __ mov(edi, Operand(ebx, EntryFrameConstants::kFunctionArgOffset)); 403 404 // Invoke the code. 405 Handle<Code> builtin = is_construct 406 ? BUILTIN_CODE(masm->isolate(), Construct) 407 : masm->isolate()->builtins()->Call(); 408 __ Call(builtin, RelocInfo::CODE_TARGET); 409 410 // Exit the internal frame. Notice that this also removes the empty. 411 // context and the function left on the stack by the code 412 // invocation. 413 } 414 __ ret(0); 415 } 416 417 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { 418 Generate_JSEntryTrampolineHelper(masm, false); 419 } 420 421 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { 422 Generate_JSEntryTrampolineHelper(masm, true); 423 } 424 425 static void GetSharedFunctionInfoBytecode(MacroAssembler* masm, 426 Register sfi_data, 427 Register scratch1) { 428 Label done; 429 430 __ CmpObjectType(sfi_data, INTERPRETER_DATA_TYPE, scratch1); 431 __ j(not_equal, &done, Label::kNear); 432 __ mov(sfi_data, 433 FieldOperand(sfi_data, InterpreterData::kBytecodeArrayOffset)); 434 435 __ bind(&done); 436 } 437 438 // static 439 void Builtins::Generate_ResumeGeneratorTrampoline(MacroAssembler* masm) { 440 // ----------- S t a t e ------------- 441 // -- eax : the value to pass to the generator 442 // -- edx : the JSGeneratorObject to resume 443 // -- esp[0] : return address 444 // ----------------------------------- 445 __ AssertGeneratorObject(edx); 446 447 // Store input value into generator object. 448 __ mov(FieldOperand(edx, JSGeneratorObject::kInputOrDebugPosOffset), eax); 449 __ RecordWriteField(edx, JSGeneratorObject::kInputOrDebugPosOffset, eax, ecx, 450 kDontSaveFPRegs); 451 452 // Load suspended function and context. 453 __ mov(edi, FieldOperand(edx, JSGeneratorObject::kFunctionOffset)); 454 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 455 456 // Flood function if we are stepping. 457 Label prepare_step_in_if_stepping, prepare_step_in_suspended_generator; 458 Label stepping_prepared; 459 ExternalReference debug_hook = 460 ExternalReference::debug_hook_on_function_call_address(masm->isolate()); 461 __ cmpb(__ StaticVariable(debug_hook), Immediate(0)); 462 __ j(not_equal, &prepare_step_in_if_stepping); 463 464 // Flood function if we need to continue stepping in the suspended generator. 465 ExternalReference debug_suspended_generator = 466 ExternalReference::debug_suspended_generator_address(masm->isolate()); 467 __ cmp(edx, __ StaticVariable(debug_suspended_generator)); 468 __ j(equal, &prepare_step_in_suspended_generator); 469 __ bind(&stepping_prepared); 470 471 // Check the stack for overflow. We are not trying to catch interruptions 472 // (i.e. debug break and preemption) here, so check the "real stack limit". 473 Label stack_overflow; 474 __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex); 475 __ j(below, &stack_overflow); 476 477 // Pop return address. 478 __ PopReturnAddressTo(eax); 479 480 // Push receiver. 481 __ Push(FieldOperand(edx, JSGeneratorObject::kReceiverOffset)); 482 483 // ----------- S t a t e ------------- 484 // -- eax : return address 485 // -- edx : the JSGeneratorObject to resume 486 // -- edi : generator function 487 // -- esi : generator context 488 // -- esp[0] : generator receiver 489 // ----------------------------------- 490 491 // Copy the function arguments from the generator object's register file. 492 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 493 __ movzx_w( 494 ecx, FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset)); 495 __ mov(ebx, 496 FieldOperand(edx, JSGeneratorObject::kParametersAndRegistersOffset)); 497 { 498 Label done_loop, loop; 499 __ Set(edi, 0); 500 501 __ bind(&loop); 502 __ cmp(edi, ecx); 503 __ j(greater_equal, &done_loop); 504 __ Push( 505 FieldOperand(ebx, edi, times_pointer_size, FixedArray::kHeaderSize)); 506 __ add(edi, Immediate(1)); 507 __ jmp(&loop); 508 509 __ bind(&done_loop); 510 __ mov(edi, FieldOperand(edx, JSGeneratorObject::kFunctionOffset)); 511 } 512 513 // Underlying function needs to have bytecode available. 514 if (FLAG_debug_code) { 515 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 516 __ mov(ecx, FieldOperand(ecx, SharedFunctionInfo::kFunctionDataOffset)); 517 __ Push(eax); 518 GetSharedFunctionInfoBytecode(masm, ecx, eax); 519 __ Pop(eax); 520 __ CmpObjectType(ecx, BYTECODE_ARRAY_TYPE, ecx); 521 __ Assert(equal, AbortReason::kMissingBytecodeArray); 522 } 523 524 // Resume (Ignition/TurboFan) generator object. 525 { 526 __ PushReturnAddressFrom(eax); 527 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 528 __ movzx_w(eax, FieldOperand( 529 eax, SharedFunctionInfo::kFormalParameterCountOffset)); 530 // We abuse new.target both to indicate that this is a resume call and to 531 // pass in the generator object. In ordinary calls, new.target is always 532 // undefined because generator functions are non-constructable. 533 static_assert(kJavaScriptCallCodeStartRegister == ecx, "ABI mismatch"); 534 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeOffset)); 535 __ add(ecx, Immediate(Code::kHeaderSize - kHeapObjectTag)); 536 __ jmp(ecx); 537 } 538 539 __ bind(&prepare_step_in_if_stepping); 540 { 541 FrameScope scope(masm, StackFrame::INTERNAL); 542 __ Push(edx); 543 __ Push(edi); 544 // Push hole as receiver since we do not use it for stepping. 545 __ PushRoot(Heap::kTheHoleValueRootIndex); 546 __ CallRuntime(Runtime::kDebugOnFunctionCall); 547 __ Pop(edx); 548 __ mov(edi, FieldOperand(edx, JSGeneratorObject::kFunctionOffset)); 549 } 550 __ jmp(&stepping_prepared); 551 552 __ bind(&prepare_step_in_suspended_generator); 553 { 554 FrameScope scope(masm, StackFrame::INTERNAL); 555 __ Push(edx); 556 __ CallRuntime(Runtime::kDebugPrepareStepInSuspendedGenerator); 557 __ Pop(edx); 558 __ mov(edi, FieldOperand(edx, JSGeneratorObject::kFunctionOffset)); 559 } 560 __ jmp(&stepping_prepared); 561 562 __ bind(&stack_overflow); 563 { 564 FrameScope scope(masm, StackFrame::INTERNAL); 565 __ CallRuntime(Runtime::kThrowStackOverflow); 566 __ int3(); // This should be unreachable. 567 } 568 } 569 570 static void ReplaceClosureCodeWithOptimizedCode( 571 MacroAssembler* masm, Register optimized_code, Register closure, 572 Register scratch1, Register scratch2, Register scratch3) { 573 574 // Store the optimized code in the closure. 575 __ mov(FieldOperand(closure, JSFunction::kCodeOffset), optimized_code); 576 __ mov(scratch1, optimized_code); // Write barrier clobbers scratch1 below. 577 __ RecordWriteField(closure, JSFunction::kCodeOffset, scratch1, scratch2, 578 kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK); 579 } 580 581 static void LeaveInterpreterFrame(MacroAssembler* masm, Register scratch1, 582 Register scratch2) { 583 Register args_count = scratch1; 584 Register return_pc = scratch2; 585 586 // Get the arguments + receiver count. 587 __ mov(args_count, 588 Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp)); 589 __ mov(args_count, 590 FieldOperand(args_count, BytecodeArray::kParameterSizeOffset)); 591 592 // Leave the frame (also dropping the register file). 593 __ leave(); 594 595 // Drop receiver + arguments. 596 __ pop(return_pc); 597 __ add(esp, args_count); 598 __ push(return_pc); 599 } 600 601 // Tail-call |function_id| if |smi_entry| == |marker| 602 static void TailCallRuntimeIfMarkerEquals(MacroAssembler* masm, 603 Register smi_entry, 604 OptimizationMarker marker, 605 Runtime::FunctionId function_id) { 606 Label no_match; 607 __ cmp(smi_entry, Immediate(Smi::FromEnum(marker))); 608 __ j(not_equal, &no_match, Label::kNear); 609 GenerateTailCallToReturnedCode(masm, function_id); 610 __ bind(&no_match); 611 } 612 613 static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm, 614 Register feedback_vector, 615 Register scratch) { 616 // ----------- S t a t e ------------- 617 // -- eax : argument count (preserved for callee if needed, and caller) 618 // -- edx : new target (preserved for callee if needed, and caller) 619 // -- edi : target function (preserved for callee if needed, and caller) 620 // -- feedback vector (preserved for caller if needed) 621 // ----------------------------------- 622 DCHECK(!AreAliased(feedback_vector, eax, edx, edi, scratch)); 623 624 Label optimized_code_slot_is_weak_ref, fallthrough; 625 626 Register closure = edi; 627 Register optimized_code_entry = scratch; 628 629 __ mov(optimized_code_entry, 630 FieldOperand(feedback_vector, FeedbackVector::kOptimizedCodeOffset)); 631 632 // Check if the code entry is a Smi. If yes, we interpret it as an 633 // optimisation marker. Otherwise, interpret it as a weak reference to a code 634 // object. 635 __ JumpIfNotSmi(optimized_code_entry, &optimized_code_slot_is_weak_ref); 636 637 { 638 // Optimized code slot is an optimization marker. 639 640 // Fall through if no optimization trigger. 641 __ cmp(optimized_code_entry, 642 Immediate(Smi::FromEnum(OptimizationMarker::kNone))); 643 __ j(equal, &fallthrough); 644 645 TailCallRuntimeIfMarkerEquals(masm, optimized_code_entry, 646 OptimizationMarker::kLogFirstExecution, 647 Runtime::kFunctionFirstExecution); 648 TailCallRuntimeIfMarkerEquals(masm, optimized_code_entry, 649 OptimizationMarker::kCompileOptimized, 650 Runtime::kCompileOptimized_NotConcurrent); 651 TailCallRuntimeIfMarkerEquals( 652 masm, optimized_code_entry, 653 OptimizationMarker::kCompileOptimizedConcurrent, 654 Runtime::kCompileOptimized_Concurrent); 655 656 { 657 // Otherwise, the marker is InOptimizationQueue, so fall through hoping 658 // that an interrupt will eventually update the slot with optimized code. 659 if (FLAG_debug_code) { 660 __ cmp( 661 optimized_code_entry, 662 Immediate(Smi::FromEnum(OptimizationMarker::kInOptimizationQueue))); 663 __ Assert(equal, AbortReason::kExpectedOptimizationSentinel); 664 } 665 __ jmp(&fallthrough); 666 } 667 } 668 669 { 670 // Optimized code slot is a weak reference. 671 __ bind(&optimized_code_slot_is_weak_ref); 672 673 __ LoadWeakValue(optimized_code_entry, &fallthrough); 674 675 __ push(eax); 676 __ push(edx); 677 678 // Check if the optimized code is marked for deopt. If it is, bailout to a 679 // given label. 680 Label found_deoptimized_code; 681 __ mov(eax, 682 FieldOperand(optimized_code_entry, Code::kCodeDataContainerOffset)); 683 __ test(FieldOperand(eax, CodeDataContainer::kKindSpecificFlagsOffset), 684 Immediate(1 << Code::kMarkedForDeoptimizationBit)); 685 __ j(not_zero, &found_deoptimized_code); 686 687 // Optimized code is good, get it into the closure and link the closure into 688 // the optimized functions list, then tail call the optimized code. 689 // The feedback vector is no longer used, so re-use it as a scratch 690 // register. 691 ReplaceClosureCodeWithOptimizedCode(masm, optimized_code_entry, closure, 692 edx, eax, feedback_vector); 693 static_assert(kJavaScriptCallCodeStartRegister == ecx, "ABI mismatch"); 694 __ Move(ecx, optimized_code_entry); 695 __ add(ecx, Immediate(Code::kHeaderSize - kHeapObjectTag)); 696 __ pop(edx); 697 __ pop(eax); 698 __ jmp(ecx); 699 700 // Optimized code slot contains deoptimized code, evict it and re-enter the 701 // closure's code. 702 __ bind(&found_deoptimized_code); 703 __ pop(edx); 704 __ pop(eax); 705 GenerateTailCallToReturnedCode(masm, Runtime::kEvictOptimizedCodeSlot); 706 } 707 708 // Fall-through if the optimized code cell is clear and there is no 709 // optimization marker. 710 __ bind(&fallthrough); 711 } 712 713 // Advance the current bytecode offset. This simulates what all bytecode 714 // handlers do upon completion of the underlying operation. Will bail out to a 715 // label if the bytecode (without prefix) is a return bytecode. 716 static void AdvanceBytecodeOffsetOrReturn(MacroAssembler* masm, 717 Register bytecode_array, 718 Register bytecode_offset, 719 Register bytecode, Register scratch1, 720 Label* if_return) { 721 Register bytecode_size_table = scratch1; 722 DCHECK(!AreAliased(bytecode_array, bytecode_offset, bytecode_size_table, 723 bytecode)); 724 725 __ Move(bytecode_size_table, 726 Immediate(ExternalReference::bytecode_size_table_address())); 727 728 // Check if the bytecode is a Wide or ExtraWide prefix bytecode. 729 Label process_bytecode, extra_wide; 730 STATIC_ASSERT(0 == static_cast<int>(interpreter::Bytecode::kWide)); 731 STATIC_ASSERT(1 == static_cast<int>(interpreter::Bytecode::kExtraWide)); 732 STATIC_ASSERT(2 == static_cast<int>(interpreter::Bytecode::kDebugBreakWide)); 733 STATIC_ASSERT(3 == 734 static_cast<int>(interpreter::Bytecode::kDebugBreakExtraWide)); 735 __ cmpb(bytecode, Immediate(0x3)); 736 __ j(above, &process_bytecode, Label::kNear); 737 __ test(bytecode, Immediate(0x1)); 738 __ j(not_equal, &extra_wide, Label::kNear); 739 740 // Load the next bytecode and update table to the wide scaled table. 741 __ inc(bytecode_offset); 742 __ movzx_b(bytecode, Operand(bytecode_array, bytecode_offset, times_1, 0)); 743 __ add(bytecode_size_table, 744 Immediate(kIntSize * interpreter::Bytecodes::kBytecodeCount)); 745 __ jmp(&process_bytecode, Label::kNear); 746 747 __ bind(&extra_wide); 748 // Load the next bytecode and update table to the extra wide scaled table. 749 __ inc(bytecode_offset); 750 __ movzx_b(bytecode, Operand(bytecode_array, bytecode_offset, times_1, 0)); 751 __ add(bytecode_size_table, 752 Immediate(2 * kIntSize * interpreter::Bytecodes::kBytecodeCount)); 753 754 __ bind(&process_bytecode); 755 756 // Bailout to the return label if this is a return bytecode. 757 #define JUMP_IF_EQUAL(NAME) \ 758 __ cmpb(bytecode, \ 759 Immediate(static_cast<int>(interpreter::Bytecode::k##NAME))); \ 760 __ j(equal, if_return); 761 RETURN_BYTECODE_LIST(JUMP_IF_EQUAL) 762 #undef JUMP_IF_EQUAL 763 764 // Otherwise, load the size of the current bytecode and advance the offset. 765 __ add(bytecode_offset, Operand(bytecode_size_table, bytecode, times_4, 0)); 766 } 767 768 // Generate code for entering a JS function with the interpreter. 769 // On entry to the function the receiver and arguments have been pushed on the 770 // stack left to right. The actual argument count matches the formal parameter 771 // count expected by the function. 772 // 773 // The live registers are: 774 // o edi: the JS function object being called 775 // o edx: the incoming new target or generator object 776 // o esi: our context 777 // o ebp: the caller's frame pointer 778 // o esp: stack pointer (pointing to return address) 779 // 780 // The function builds an interpreter frame. See InterpreterFrameConstants in 781 // frames.h for its layout. 782 void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) { 783 ProfileEntryHookStub::MaybeCallEntryHook(masm); 784 785 Register closure = edi; 786 Register feedback_vector = ebx; 787 788 // Load the feedback vector from the closure. 789 __ mov(feedback_vector, 790 FieldOperand(closure, JSFunction::kFeedbackCellOffset)); 791 __ mov(feedback_vector, FieldOperand(feedback_vector, Cell::kValueOffset)); 792 // Read off the optimized code slot in the feedback vector, and if there 793 // is optimized code or an optimization marker, call that instead. 794 MaybeTailCallOptimizedCodeSlot(masm, feedback_vector, ecx); 795 796 // Open a frame scope to indicate that there is a frame on the stack. The 797 // MANUAL indicates that the scope shouldn't actually generate code to set 798 // up the frame (that is done below). 799 FrameScope frame_scope(masm, StackFrame::MANUAL); 800 __ push(ebp); // Caller's frame pointer. 801 __ mov(ebp, esp); 802 __ push(esi); // Callee's context. 803 __ push(edi); // Callee's JS function. 804 805 // Get the bytecode array from the function object and load it into 806 // kInterpreterBytecodeArrayRegister. 807 __ mov(eax, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 808 __ mov(kInterpreterBytecodeArrayRegister, 809 FieldOperand(eax, SharedFunctionInfo::kFunctionDataOffset)); 810 __ Push(eax); 811 GetSharedFunctionInfoBytecode(masm, kInterpreterBytecodeArrayRegister, eax); 812 __ Pop(eax); 813 814 __ inc(FieldOperand(feedback_vector, FeedbackVector::kInvocationCountOffset)); 815 816 // Check function data field is actually a BytecodeArray object. 817 if (FLAG_debug_code) { 818 __ AssertNotSmi(kInterpreterBytecodeArrayRegister); 819 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE, 820 eax); 821 __ Assert( 822 equal, 823 AbortReason::kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry); 824 } 825 826 // Reset code age. 827 __ mov_b(FieldOperand(kInterpreterBytecodeArrayRegister, 828 BytecodeArray::kBytecodeAgeOffset), 829 Immediate(BytecodeArray::kNoAgeBytecodeAge)); 830 831 // Push bytecode array. 832 __ push(kInterpreterBytecodeArrayRegister); 833 // Push Smi tagged initial bytecode array offset. 834 __ push(Immediate(Smi::FromInt(BytecodeArray::kHeaderSize - kHeapObjectTag))); 835 836 // Allocate the local and temporary register file on the stack. 837 { 838 // Load frame size from the BytecodeArray object. 839 __ mov(ebx, FieldOperand(kInterpreterBytecodeArrayRegister, 840 BytecodeArray::kFrameSizeOffset)); 841 842 // Do a stack check to ensure we don't go over the limit. 843 Label ok; 844 __ mov(ecx, esp); 845 __ sub(ecx, ebx); 846 ExternalReference stack_limit = 847 ExternalReference::address_of_real_stack_limit(masm->isolate()); 848 __ cmp(ecx, __ StaticVariable(stack_limit)); 849 __ j(above_equal, &ok); 850 __ CallRuntime(Runtime::kThrowStackOverflow); 851 __ bind(&ok); 852 853 // If ok, push undefined as the initial value for all register file entries. 854 Label loop_header; 855 Label loop_check; 856 __ mov(eax, Immediate(masm->isolate()->factory()->undefined_value())); 857 __ jmp(&loop_check); 858 __ bind(&loop_header); 859 // TODO(rmcilroy): Consider doing more than one push per loop iteration. 860 __ push(eax); 861 // Continue loop if not done. 862 __ bind(&loop_check); 863 __ sub(ebx, Immediate(kPointerSize)); 864 __ j(greater_equal, &loop_header); 865 } 866 867 // If the bytecode array has a valid incoming new target or generator object 868 // register, initialize it with incoming value which was passed in edx. 869 Label no_incoming_new_target_or_generator_register; 870 __ mov(eax, FieldOperand( 871 kInterpreterBytecodeArrayRegister, 872 BytecodeArray::kIncomingNewTargetOrGeneratorRegisterOffset)); 873 __ test(eax, eax); 874 __ j(zero, &no_incoming_new_target_or_generator_register); 875 __ mov(Operand(ebp, eax, times_pointer_size, 0), edx); 876 __ bind(&no_incoming_new_target_or_generator_register); 877 878 // Load accumulator and bytecode offset into registers. 879 __ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex); 880 __ mov(kInterpreterBytecodeOffsetRegister, 881 Immediate(BytecodeArray::kHeaderSize - kHeapObjectTag)); 882 883 // Load the dispatch table into a register and dispatch to the bytecode 884 // handler at the current bytecode offset. 885 Label do_dispatch; 886 __ bind(&do_dispatch); 887 __ mov(kInterpreterDispatchTableRegister, 888 Immediate(ExternalReference::interpreter_dispatch_table_address( 889 masm->isolate()))); 890 __ movzx_b(ebx, Operand(kInterpreterBytecodeArrayRegister, 891 kInterpreterBytecodeOffsetRegister, times_1, 0)); 892 __ mov( 893 kJavaScriptCallCodeStartRegister, 894 Operand(kInterpreterDispatchTableRegister, ebx, times_pointer_size, 0)); 895 __ call(kJavaScriptCallCodeStartRegister); 896 masm->isolate()->heap()->SetInterpreterEntryReturnPCOffset(masm->pc_offset()); 897 898 // Any returns to the entry trampoline are either due to the return bytecode 899 // or the interpreter tail calling a builtin and then a dispatch. 900 901 // Get bytecode array and bytecode offset from the stack frame. 902 __ mov(kInterpreterBytecodeArrayRegister, 903 Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp)); 904 __ mov(kInterpreterBytecodeOffsetRegister, 905 Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); 906 __ SmiUntag(kInterpreterBytecodeOffsetRegister); 907 908 // Either return, or advance to the next bytecode and dispatch. 909 Label do_return; 910 __ movzx_b(ebx, Operand(kInterpreterBytecodeArrayRegister, 911 kInterpreterBytecodeOffsetRegister, times_1, 0)); 912 AdvanceBytecodeOffsetOrReturn(masm, kInterpreterBytecodeArrayRegister, 913 kInterpreterBytecodeOffsetRegister, ebx, ecx, 914 &do_return); 915 __ jmp(&do_dispatch); 916 917 __ bind(&do_return); 918 // The return value is in eax. 919 LeaveInterpreterFrame(masm, ebx, ecx); 920 __ ret(0); 921 } 922 923 924 static void Generate_InterpreterPushArgs(MacroAssembler* masm, 925 Register array_limit, 926 Register start_address) { 927 // ----------- S t a t e ------------- 928 // -- start_address : Pointer to the last argument in the args array. 929 // -- array_limit : Pointer to one before the first argument in the 930 // args array. 931 // ----------------------------------- 932 Label loop_header, loop_check; 933 __ jmp(&loop_check); 934 __ bind(&loop_header); 935 __ Push(Operand(start_address, 0)); 936 __ sub(start_address, Immediate(kPointerSize)); 937 __ bind(&loop_check); 938 __ cmp(start_address, array_limit); 939 __ j(greater, &loop_header, Label::kNear); 940 } 941 942 // static 943 void Builtins::Generate_InterpreterPushArgsThenCallImpl( 944 MacroAssembler* masm, ConvertReceiverMode receiver_mode, 945 InterpreterPushArgsMode mode) { 946 DCHECK(mode != InterpreterPushArgsMode::kArrayFunction); 947 // ----------- S t a t e ------------- 948 // -- eax : the number of arguments (not including the receiver) 949 // -- ebx : the address of the first argument to be pushed. Subsequent 950 // arguments should be consecutive above this, in the same order as 951 // they are to be pushed onto the stack. 952 // -- edi : the target to call (can be any Object). 953 // ----------------------------------- 954 Label stack_overflow; 955 // Compute the expected number of arguments. 956 __ mov(ecx, eax); 957 __ add(ecx, Immediate(1)); // Add one for receiver. 958 959 // Add a stack check before pushing the arguments. We need an extra register 960 // to perform a stack check. So push it onto the stack temporarily. This 961 // might cause stack overflow, but it will be detected by the check. 962 __ Push(edi); 963 Generate_StackOverflowCheck(masm, ecx, edx, edi, &stack_overflow); 964 __ Pop(edi); 965 966 // Pop return address to allow tail-call after pushing arguments. 967 __ Pop(edx); 968 969 // Push "undefined" as the receiver arg if we need to. 970 if (receiver_mode == ConvertReceiverMode::kNullOrUndefined) { 971 __ PushRoot(Heap::kUndefinedValueRootIndex); 972 __ sub(ecx, Immediate(1)); // Subtract one for receiver. 973 } 974 975 // Find the address of the last argument. 976 __ shl(ecx, kPointerSizeLog2); 977 __ neg(ecx); 978 __ add(ecx, ebx); 979 Generate_InterpreterPushArgs(masm, ecx, ebx); 980 981 if (mode == InterpreterPushArgsMode::kWithFinalSpread) { 982 __ Pop(ebx); // Pass the spread in a register 983 __ sub(eax, Immediate(1)); // Subtract one for spread 984 } 985 986 // Call the target. 987 __ Push(edx); // Re-push return address. 988 989 if (mode == InterpreterPushArgsMode::kWithFinalSpread) { 990 __ Jump(BUILTIN_CODE(masm->isolate(), CallWithSpread), 991 RelocInfo::CODE_TARGET); 992 } else { 993 __ Jump(masm->isolate()->builtins()->Call(ConvertReceiverMode::kAny), 994 RelocInfo::CODE_TARGET); 995 } 996 997 __ bind(&stack_overflow); 998 { 999 // Pop the temporary registers, so that return address is on top of stack. 1000 __ Pop(edi); 1001 1002 __ TailCallRuntime(Runtime::kThrowStackOverflow); 1003 1004 // This should be unreachable. 1005 __ int3(); 1006 } 1007 } 1008 1009 namespace { 1010 1011 // This function modified start_addr, and only reads the contents of num_args 1012 // register. scratch1 and scratch2 are used as temporary registers. Their 1013 // original values are restored after the use. 1014 void Generate_InterpreterPushZeroAndArgsAndReturnAddress( 1015 MacroAssembler* masm, Register num_args, Register start_addr, 1016 Register scratch1, Register scratch2, int num_slots_above_ret_addr, 1017 Label* stack_overflow) { 1018 // We have to move return address and the temporary registers above it 1019 // before we can copy arguments onto the stack. To achieve this: 1020 // Step 1: Increment the stack pointer by num_args + 1 (for receiver). 1021 // Step 2: Move the return address and values above it to the top of stack. 1022 // Step 3: Copy the arguments into the correct locations. 1023 // current stack =====> required stack layout 1024 // | | | scratch1 | (2) <-- esp(1) 1025 // | | | .... | (2) 1026 // | | | scratch-n | (2) 1027 // | | | return addr | (2) 1028 // | | | arg N | (3) 1029 // | scratch1 | <-- esp | .... | 1030 // | .... | | arg 1 | 1031 // | scratch-n | | arg 0 | 1032 // | return addr | | receiver slot | 1033 1034 // Check for stack overflow before we increment the stack pointer. 1035 Generate_StackOverflowCheck(masm, num_args, scratch1, scratch2, 1036 stack_overflow, true); 1037 1038 // Step 1 - Update the stack pointer. scratch1 already contains the required 1039 // increment to the stack. i.e. num_args + 1 stack slots. This is computed in 1040 // Generate_StackOverflowCheck. 1041 1042 __ AllocateStackFrame(scratch1); 1043 1044 // Step 2 move return_address and slots above it to the correct locations. 1045 // Move from top to bottom, otherwise we may overwrite when num_args = 0 or 1, 1046 // basically when the source and destination overlap. We at least need one 1047 // extra slot for receiver, so no extra checks are required to avoid copy. 1048 for (int i = 0; i < num_slots_above_ret_addr + 1; i++) { 1049 __ mov(scratch1, 1050 Operand(esp, num_args, times_pointer_size, (i + 1) * kPointerSize)); 1051 __ mov(Operand(esp, i * kPointerSize), scratch1); 1052 } 1053 1054 // Step 3 copy arguments to correct locations. 1055 // Slot meant for receiver contains return address. Reset it so that 1056 // we will not incorrectly interpret return address as an object. 1057 __ mov(Operand(esp, num_args, times_pointer_size, 1058 (num_slots_above_ret_addr + 1) * kPointerSize), 1059 Immediate(0)); 1060 __ mov(scratch1, num_args); 1061 1062 Label loop_header, loop_check; 1063 __ jmp(&loop_check); 1064 __ bind(&loop_header); 1065 __ mov(scratch2, Operand(start_addr, 0)); 1066 __ mov(Operand(esp, scratch1, times_pointer_size, 1067 num_slots_above_ret_addr * kPointerSize), 1068 scratch2); 1069 __ sub(start_addr, Immediate(kPointerSize)); 1070 __ sub(scratch1, Immediate(1)); 1071 __ bind(&loop_check); 1072 __ cmp(scratch1, Immediate(0)); 1073 __ j(greater, &loop_header, Label::kNear); 1074 } 1075 1076 } // end anonymous namespace 1077 1078 // static 1079 void Builtins::Generate_InterpreterPushArgsThenConstructImpl( 1080 MacroAssembler* masm, InterpreterPushArgsMode mode) { 1081 // ----------- S t a t e ------------- 1082 // -- eax : the number of arguments (not including the receiver) 1083 // -- edx : the new target 1084 // -- edi : the constructor 1085 // -- ebx : allocation site feedback (if available or undefined) 1086 // -- ecx : the address of the first argument to be pushed. Subsequent 1087 // arguments should be consecutive above this, in the same order as 1088 // they are to be pushed onto the stack. 1089 // ----------------------------------- 1090 Label stack_overflow; 1091 // We need two scratch registers. Push edi and edx onto stack. 1092 __ Push(edi); 1093 __ Push(edx); 1094 1095 // Push arguments and move return address to the top of stack. 1096 // The eax register is readonly. The ecx register will be modified. The edx 1097 // and edi registers will be modified but restored to their original values. 1098 Generate_InterpreterPushZeroAndArgsAndReturnAddress(masm, eax, ecx, edx, edi, 1099 2, &stack_overflow); 1100 1101 // Restore edi and edx 1102 __ Pop(edx); 1103 __ Pop(edi); 1104 1105 if (mode == InterpreterPushArgsMode::kWithFinalSpread) { 1106 __ PopReturnAddressTo(ecx); 1107 __ Pop(ebx); // Pass the spread in a register 1108 __ PushReturnAddressFrom(ecx); 1109 __ sub(eax, Immediate(1)); // Subtract one for spread 1110 } else { 1111 __ AssertUndefinedOrAllocationSite(ebx); 1112 } 1113 1114 if (mode == InterpreterPushArgsMode::kArrayFunction) { 1115 // Tail call to the array construct stub (still in the caller 1116 // context at this point). 1117 __ AssertFunction(edi); 1118 // TODO(v8:6666): When rewriting ia32 ASM builtins to not clobber the 1119 // kRootRegister ebx, this useless move can be removed. 1120 __ Move(kJavaScriptCallExtraArg1Register, ebx); 1121 Handle<Code> code = BUILTIN_CODE(masm->isolate(), ArrayConstructorImpl); 1122 __ Jump(code, RelocInfo::CODE_TARGET); 1123 } else if (mode == InterpreterPushArgsMode::kWithFinalSpread) { 1124 // Call the constructor with unmodified eax, edi, edx values. 1125 __ Jump(BUILTIN_CODE(masm->isolate(), ConstructWithSpread), 1126 RelocInfo::CODE_TARGET); 1127 } else { 1128 DCHECK_EQ(InterpreterPushArgsMode::kOther, mode); 1129 // Call the constructor with unmodified eax, edi, edx values. 1130 __ Jump(BUILTIN_CODE(masm->isolate(), Construct), RelocInfo::CODE_TARGET); 1131 } 1132 1133 __ bind(&stack_overflow); 1134 { 1135 // Pop the temporary registers, so that return address is on top of stack. 1136 __ Pop(edx); 1137 __ Pop(edi); 1138 1139 __ TailCallRuntime(Runtime::kThrowStackOverflow); 1140 1141 // This should be unreachable. 1142 __ int3(); 1143 } 1144 } 1145 1146 static void Generate_InterpreterEnterBytecode(MacroAssembler* masm) { 1147 // Set the return address to the correct point in the interpreter entry 1148 // trampoline. 1149 Label builtin_trampoline, trampoline_loaded; 1150 Smi* interpreter_entry_return_pc_offset( 1151 masm->isolate()->heap()->interpreter_entry_return_pc_offset()); 1152 DCHECK_NE(interpreter_entry_return_pc_offset, Smi::kZero); 1153 1154 // If the SFI function_data is an InterpreterData, get the trampoline stored 1155 // in it, otherwise get the trampoline from the builtins list. 1156 __ mov(ebx, Operand(ebp, StandardFrameConstants::kFunctionOffset)); 1157 __ mov(ebx, FieldOperand(ebx, JSFunction::kSharedFunctionInfoOffset)); 1158 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kFunctionDataOffset)); 1159 __ Push(eax); 1160 __ CmpObjectType(ebx, INTERPRETER_DATA_TYPE, eax); 1161 __ j(not_equal, &builtin_trampoline, Label::kNear); 1162 1163 __ mov(ebx, FieldOperand(ebx, InterpreterData::kInterpreterTrampolineOffset)); 1164 __ jmp(&trampoline_loaded, Label::kNear); 1165 1166 __ bind(&builtin_trampoline); 1167 __ Move(ebx, BUILTIN_CODE(masm->isolate(), InterpreterEntryTrampoline)); 1168 1169 __ bind(&trampoline_loaded); 1170 __ Pop(eax); 1171 __ add(ebx, Immediate(interpreter_entry_return_pc_offset->value() + 1172 Code::kHeaderSize - kHeapObjectTag)); 1173 __ push(ebx); 1174 1175 // Initialize the dispatch table register. 1176 __ mov(kInterpreterDispatchTableRegister, 1177 Immediate(ExternalReference::interpreter_dispatch_table_address( 1178 masm->isolate()))); 1179 1180 // Get the bytecode array pointer from the frame. 1181 __ mov(kInterpreterBytecodeArrayRegister, 1182 Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp)); 1183 1184 if (FLAG_debug_code) { 1185 // Check function data field is actually a BytecodeArray object. 1186 __ AssertNotSmi(kInterpreterBytecodeArrayRegister); 1187 __ CmpObjectType(kInterpreterBytecodeArrayRegister, BYTECODE_ARRAY_TYPE, 1188 ebx); 1189 __ Assert( 1190 equal, 1191 AbortReason::kFunctionDataShouldBeBytecodeArrayOnInterpreterEntry); 1192 } 1193 1194 // Get the target bytecode offset from the frame. 1195 __ mov(kInterpreterBytecodeOffsetRegister, 1196 Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); 1197 __ SmiUntag(kInterpreterBytecodeOffsetRegister); 1198 1199 // Dispatch to the target bytecode. 1200 __ movzx_b(ebx, Operand(kInterpreterBytecodeArrayRegister, 1201 kInterpreterBytecodeOffsetRegister, times_1, 0)); 1202 __ mov( 1203 kJavaScriptCallCodeStartRegister, 1204 Operand(kInterpreterDispatchTableRegister, ebx, times_pointer_size, 0)); 1205 __ jmp(kJavaScriptCallCodeStartRegister); 1206 } 1207 1208 void Builtins::Generate_InterpreterEnterBytecodeAdvance(MacroAssembler* masm) { 1209 // Get bytecode array and bytecode offset from the stack frame. 1210 __ mov(kInterpreterBytecodeArrayRegister, 1211 Operand(ebp, InterpreterFrameConstants::kBytecodeArrayFromFp)); 1212 __ mov(kInterpreterBytecodeOffsetRegister, 1213 Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp)); 1214 __ SmiUntag(kInterpreterBytecodeOffsetRegister); 1215 1216 // Load the current bytecode 1217 __ movzx_b(ebx, Operand(kInterpreterBytecodeArrayRegister, 1218 kInterpreterBytecodeOffsetRegister, times_1, 0)); 1219 1220 // Advance to the next bytecode. 1221 Label if_return; 1222 AdvanceBytecodeOffsetOrReturn(masm, kInterpreterBytecodeArrayRegister, 1223 kInterpreterBytecodeOffsetRegister, ebx, ecx, 1224 &if_return); 1225 1226 // Convert new bytecode offset to a Smi and save in the stackframe. 1227 __ mov(ebx, kInterpreterBytecodeOffsetRegister); 1228 __ SmiTag(ebx); 1229 __ mov(Operand(ebp, InterpreterFrameConstants::kBytecodeOffsetFromFp), ebx); 1230 1231 Generate_InterpreterEnterBytecode(masm); 1232 1233 // We should never take the if_return path. 1234 __ bind(&if_return); 1235 __ Abort(AbortReason::kInvalidBytecodeAdvance); 1236 } 1237 1238 void Builtins::Generate_InterpreterEnterBytecodeDispatch(MacroAssembler* masm) { 1239 Generate_InterpreterEnterBytecode(masm); 1240 } 1241 1242 void Builtins::Generate_InstantiateAsmJs(MacroAssembler* masm) { 1243 // ----------- S t a t e ------------- 1244 // -- eax : argument count (preserved for callee) 1245 // -- edx : new target (preserved for callee) 1246 // -- edi : target function (preserved for callee) 1247 // ----------------------------------- 1248 Label failed; 1249 { 1250 FrameScope scope(masm, StackFrame::INTERNAL); 1251 // Preserve argument count for later compare. 1252 __ mov(ecx, eax); 1253 // Push the number of arguments to the callee. 1254 __ SmiTag(eax); 1255 __ push(eax); 1256 // Push a copy of the target function and the new target. 1257 __ push(edi); 1258 __ push(edx); 1259 1260 // The function. 1261 __ push(edi); 1262 // Copy arguments from caller (stdlib, foreign, heap). 1263 Label args_done; 1264 for (int j = 0; j < 4; ++j) { 1265 Label over; 1266 if (j < 3) { 1267 __ cmp(ecx, Immediate(j)); 1268 __ j(not_equal, &over, Label::kNear); 1269 } 1270 for (int i = j - 1; i >= 0; --i) { 1271 __ Push(Operand( 1272 ebp, StandardFrameConstants::kCallerSPOffset + i * kPointerSize)); 1273 } 1274 for (int i = 0; i < 3 - j; ++i) { 1275 __ PushRoot(Heap::kUndefinedValueRootIndex); 1276 } 1277 if (j < 3) { 1278 __ jmp(&args_done, Label::kNear); 1279 __ bind(&over); 1280 } 1281 } 1282 __ bind(&args_done); 1283 1284 // Call runtime, on success unwind frame, and parent frame. 1285 __ CallRuntime(Runtime::kInstantiateAsmJs, 4); 1286 // A smi 0 is returned on failure, an object on success. 1287 __ JumpIfSmi(eax, &failed, Label::kNear); 1288 1289 __ Drop(2); 1290 __ Pop(ecx); 1291 __ SmiUntag(ecx); 1292 scope.GenerateLeaveFrame(); 1293 1294 __ PopReturnAddressTo(ebx); 1295 __ inc(ecx); 1296 __ lea(esp, Operand(esp, ecx, times_pointer_size, 0)); 1297 __ PushReturnAddressFrom(ebx); 1298 __ ret(0); 1299 1300 __ bind(&failed); 1301 // Restore target function and new target. 1302 __ pop(edx); 1303 __ pop(edi); 1304 __ pop(eax); 1305 __ SmiUntag(eax); 1306 } 1307 // On failure, tail call back to regular js by re-calling the function 1308 // which has be reset to the compile lazy builtin. 1309 static_assert(kJavaScriptCallCodeStartRegister == ecx, "ABI mismatch"); 1310 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeOffset)); 1311 __ add(ecx, Immediate(Code::kHeaderSize - kHeapObjectTag)); 1312 __ jmp(ecx); 1313 } 1314 1315 namespace { 1316 void Generate_ContinueToBuiltinHelper(MacroAssembler* masm, 1317 bool java_script_builtin, 1318 bool with_result) { 1319 const RegisterConfiguration* config(RegisterConfiguration::Default()); 1320 int allocatable_register_count = config->num_allocatable_general_registers(); 1321 if (with_result) { 1322 // Overwrite the hole inserted by the deoptimizer with the return value from 1323 // the LAZY deopt point. 1324 __ mov(Operand(esp, 1325 config->num_allocatable_general_registers() * kPointerSize + 1326 BuiltinContinuationFrameConstants::kFixedFrameSize), 1327 eax); 1328 } 1329 for (int i = allocatable_register_count - 1; i >= 0; --i) { 1330 int code = config->GetAllocatableGeneralCode(i); 1331 __ pop(Register::from_code(code)); 1332 if (java_script_builtin && code == kJavaScriptCallArgCountRegister.code()) { 1333 __ SmiUntag(Register::from_code(code)); 1334 } 1335 } 1336 __ mov( 1337 ebp, 1338 Operand(esp, BuiltinContinuationFrameConstants::kFixedFrameSizeFromFp)); 1339 const int offsetToPC = 1340 BuiltinContinuationFrameConstants::kFixedFrameSizeFromFp - kPointerSize; 1341 __ pop(Operand(esp, offsetToPC)); 1342 __ Drop(offsetToPC / kPointerSize); 1343 __ add(Operand(esp, 0), Immediate(Code::kHeaderSize - kHeapObjectTag)); 1344 __ ret(0); 1345 } 1346 } // namespace 1347 1348 void Builtins::Generate_ContinueToCodeStubBuiltin(MacroAssembler* masm) { 1349 Generate_ContinueToBuiltinHelper(masm, false, false); 1350 } 1351 1352 void Builtins::Generate_ContinueToCodeStubBuiltinWithResult( 1353 MacroAssembler* masm) { 1354 Generate_ContinueToBuiltinHelper(masm, false, true); 1355 } 1356 1357 void Builtins::Generate_ContinueToJavaScriptBuiltin(MacroAssembler* masm) { 1358 Generate_ContinueToBuiltinHelper(masm, true, false); 1359 } 1360 1361 void Builtins::Generate_ContinueToJavaScriptBuiltinWithResult( 1362 MacroAssembler* masm) { 1363 Generate_ContinueToBuiltinHelper(masm, true, true); 1364 } 1365 1366 void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) { 1367 { 1368 FrameScope scope(masm, StackFrame::INTERNAL); 1369 __ CallRuntime(Runtime::kNotifyDeoptimized); 1370 // Tear down internal frame. 1371 } 1372 1373 DCHECK_EQ(kInterpreterAccumulatorRegister.code(), eax.code()); 1374 __ mov(eax, Operand(esp, 1 * kPointerSize)); 1375 __ ret(1 * kPointerSize); // Remove eax. 1376 } 1377 1378 // static 1379 void Builtins::Generate_FunctionPrototypeApply(MacroAssembler* masm) { 1380 // ----------- S t a t e ------------- 1381 // -- eax : argc 1382 // -- esp[0] : return address 1383 // -- esp[4] : argArray 1384 // -- esp[8] : thisArg 1385 // -- esp[12] : receiver 1386 // ----------------------------------- 1387 1388 // 1. Load receiver into edi, argArray into ebx (if present), remove all 1389 // arguments from the stack (including the receiver), and push thisArg (if 1390 // present) instead. 1391 { 1392 Label no_arg_array, no_this_arg; 1393 __ LoadRoot(edx, Heap::kUndefinedValueRootIndex); 1394 __ mov(ebx, edx); 1395 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); 1396 __ test(eax, eax); 1397 __ j(zero, &no_this_arg, Label::kNear); 1398 { 1399 __ mov(edx, Operand(esp, eax, times_pointer_size, 0)); 1400 __ cmp(eax, Immediate(1)); 1401 __ j(equal, &no_arg_array, Label::kNear); 1402 __ mov(ebx, Operand(esp, eax, times_pointer_size, -kPointerSize)); 1403 __ bind(&no_arg_array); 1404 } 1405 __ bind(&no_this_arg); 1406 __ PopReturnAddressTo(ecx); 1407 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); 1408 __ Push(edx); 1409 __ PushReturnAddressFrom(ecx); 1410 } 1411 1412 // ----------- S t a t e ------------- 1413 // -- ebx : argArray 1414 // -- edi : receiver 1415 // -- esp[0] : return address 1416 // -- esp[4] : thisArg 1417 // ----------------------------------- 1418 1419 // 2. We don't need to check explicitly for callable receiver here, 1420 // since that's the first thing the Call/CallWithArrayLike builtins 1421 // will do. 1422 1423 // 3. Tail call with no arguments if argArray is null or undefined. 1424 Label no_arguments; 1425 __ JumpIfRoot(ebx, Heap::kNullValueRootIndex, &no_arguments, Label::kNear); 1426 __ JumpIfRoot(ebx, Heap::kUndefinedValueRootIndex, &no_arguments, 1427 Label::kNear); 1428 1429 // 4a. Apply the receiver to the given argArray. 1430 __ Jump(BUILTIN_CODE(masm->isolate(), CallWithArrayLike), 1431 RelocInfo::CODE_TARGET); 1432 1433 // 4b. The argArray is either null or undefined, so we tail call without any 1434 // arguments to the receiver. 1435 __ bind(&no_arguments); 1436 { 1437 __ Set(eax, 0); 1438 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); 1439 } 1440 } 1441 1442 // static 1443 void Builtins::Generate_FunctionPrototypeCall(MacroAssembler* masm) { 1444 // Stack Layout: 1445 // esp[0] : Return address 1446 // esp[8] : Argument n 1447 // esp[16] : Argument n-1 1448 // ... 1449 // esp[8 * n] : Argument 1 1450 // esp[8 * (n + 1)] : Receiver (callable to call) 1451 // 1452 // eax contains the number of arguments, n, not counting the receiver. 1453 // 1454 // 1. Make sure we have at least one argument. 1455 { 1456 Label done; 1457 __ test(eax, eax); 1458 __ j(not_zero, &done, Label::kNear); 1459 __ PopReturnAddressTo(ebx); 1460 __ PushRoot(Heap::kUndefinedValueRootIndex); 1461 __ PushReturnAddressFrom(ebx); 1462 __ inc(eax); 1463 __ bind(&done); 1464 } 1465 1466 // 2. Get the callable to call (passed as receiver) from the stack. 1467 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); 1468 1469 // 3. Shift arguments and return address one slot down on the stack 1470 // (overwriting the original receiver). Adjust argument count to make 1471 // the original first argument the new receiver. 1472 { 1473 Label loop; 1474 __ mov(ecx, eax); 1475 __ bind(&loop); 1476 __ mov(ebx, Operand(esp, ecx, times_pointer_size, 0)); 1477 __ mov(Operand(esp, ecx, times_pointer_size, kPointerSize), ebx); 1478 __ dec(ecx); 1479 __ j(not_sign, &loop); // While non-negative (to copy return address). 1480 __ pop(ebx); // Discard copy of return address. 1481 __ dec(eax); // One fewer argument (first argument is new receiver). 1482 } 1483 1484 // 4. Call the callable. 1485 __ Jump(masm->isolate()->builtins()->Call(), RelocInfo::CODE_TARGET); 1486 } 1487 1488 void Builtins::Generate_ReflectApply(MacroAssembler* masm) { 1489 // ----------- S t a t e ------------- 1490 // -- eax : argc 1491 // -- esp[0] : return address 1492 // -- esp[4] : argumentsList 1493 // -- esp[8] : thisArgument 1494 // -- esp[12] : target 1495 // -- esp[16] : receiver 1496 // ----------------------------------- 1497 1498 // 1. Load target into edi (if present), argumentsList into ebx (if present), 1499 // remove all arguments from the stack (including the receiver), and push 1500 // thisArgument (if present) instead. 1501 { 1502 Label done; 1503 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex); 1504 __ mov(edx, edi); 1505 __ mov(ebx, edi); 1506 __ cmp(eax, Immediate(1)); 1507 __ j(below, &done, Label::kNear); 1508 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize)); 1509 __ j(equal, &done, Label::kNear); 1510 __ mov(edx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize)); 1511 __ cmp(eax, Immediate(3)); 1512 __ j(below, &done, Label::kNear); 1513 __ mov(ebx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize)); 1514 __ bind(&done); 1515 __ PopReturnAddressTo(ecx); 1516 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); 1517 __ Push(edx); 1518 __ PushReturnAddressFrom(ecx); 1519 } 1520 1521 // ----------- S t a t e ------------- 1522 // -- ebx : argumentsList 1523 // -- edi : target 1524 // -- esp[0] : return address 1525 // -- esp[4] : thisArgument 1526 // ----------------------------------- 1527 1528 // 2. We don't need to check explicitly for callable target here, 1529 // since that's the first thing the Call/CallWithArrayLike builtins 1530 // will do. 1531 1532 // 3. Apply the target to the given argumentsList. 1533 __ Jump(BUILTIN_CODE(masm->isolate(), CallWithArrayLike), 1534 RelocInfo::CODE_TARGET); 1535 } 1536 1537 void Builtins::Generate_ReflectConstruct(MacroAssembler* masm) { 1538 // ----------- S t a t e ------------- 1539 // -- eax : argc 1540 // -- esp[0] : return address 1541 // -- esp[4] : new.target (optional) 1542 // -- esp[8] : argumentsList 1543 // -- esp[12] : target 1544 // -- esp[16] : receiver 1545 // ----------------------------------- 1546 1547 // 1. Load target into edi (if present), argumentsList into ebx (if present), 1548 // new.target into edx (if present, otherwise use target), remove all 1549 // arguments from the stack (including the receiver), and push thisArgument 1550 // (if present) instead. 1551 { 1552 Label done; 1553 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex); 1554 __ mov(edx, edi); 1555 __ mov(ebx, edi); 1556 __ cmp(eax, Immediate(1)); 1557 __ j(below, &done, Label::kNear); 1558 __ mov(edi, Operand(esp, eax, times_pointer_size, -0 * kPointerSize)); 1559 __ mov(edx, edi); 1560 __ j(equal, &done, Label::kNear); 1561 __ mov(ebx, Operand(esp, eax, times_pointer_size, -1 * kPointerSize)); 1562 __ cmp(eax, Immediate(3)); 1563 __ j(below, &done, Label::kNear); 1564 __ mov(edx, Operand(esp, eax, times_pointer_size, -2 * kPointerSize)); 1565 __ bind(&done); 1566 __ PopReturnAddressTo(ecx); 1567 __ lea(esp, Operand(esp, eax, times_pointer_size, kPointerSize)); 1568 __ PushRoot(Heap::kUndefinedValueRootIndex); 1569 __ PushReturnAddressFrom(ecx); 1570 } 1571 1572 // ----------- S t a t e ------------- 1573 // -- ebx : argumentsList 1574 // -- edx : new.target 1575 // -- edi : target 1576 // -- esp[0] : return address 1577 // -- esp[4] : receiver (undefined) 1578 // ----------------------------------- 1579 1580 // 2. We don't need to check explicitly for constructor target here, 1581 // since that's the first thing the Construct/ConstructWithArrayLike 1582 // builtins will do. 1583 1584 // 3. We don't need to check explicitly for constructor new.target here, 1585 // since that's the second thing the Construct/ConstructWithArrayLike 1586 // builtins will do. 1587 1588 // 4. Construct the target with the given new.target and argumentsList. 1589 __ Jump(BUILTIN_CODE(masm->isolate(), ConstructWithArrayLike), 1590 RelocInfo::CODE_TARGET); 1591 } 1592 1593 void Builtins::Generate_InternalArrayConstructor(MacroAssembler* masm) { 1594 // ----------- S t a t e ------------- 1595 // -- eax : argc 1596 // -- esp[0] : return address 1597 // -- esp[4] : last argument 1598 // ----------------------------------- 1599 Label generic_array_code; 1600 1601 if (FLAG_debug_code) { 1602 // Initial map for the builtin InternalArray function should be a map. 1603 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 1604 // Will both indicate a nullptr and a Smi. 1605 __ test(ebx, Immediate(kSmiTagMask)); 1606 __ Assert(not_zero, 1607 AbortReason::kUnexpectedInitialMapForInternalArrayFunction); 1608 __ CmpObjectType(ebx, MAP_TYPE, ecx); 1609 __ Assert(equal, 1610 AbortReason::kUnexpectedInitialMapForInternalArrayFunction); 1611 } 1612 1613 // Run the native code for the InternalArray function called as a normal 1614 // function. 1615 __ mov(ebx, masm->isolate()->factory()->undefined_value()); 1616 __ Jump(BUILTIN_CODE(masm->isolate(), InternalArrayConstructorImpl), 1617 RelocInfo::CODE_TARGET); 1618 } 1619 1620 static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) { 1621 __ push(ebp); 1622 __ mov(ebp, esp); 1623 1624 // Store the arguments adaptor context sentinel. 1625 __ push(Immediate(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR))); 1626 1627 // Push the function on the stack. 1628 __ push(edi); 1629 1630 // Preserve the number of arguments on the stack. Must preserve eax, 1631 // ebx and ecx because these registers are used when copying the 1632 // arguments and the receiver. 1633 STATIC_ASSERT(kSmiTagSize == 1); 1634 __ lea(edi, Operand(eax, eax, times_1, kSmiTag)); 1635 __ push(edi); 1636 1637 __ Push(Immediate(0)); // Padding. 1638 } 1639 1640 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { 1641 // Retrieve the number of arguments from the stack. 1642 __ mov(ebx, Operand(ebp, ArgumentsAdaptorFrameConstants::kLengthOffset)); 1643 1644 // Leave the frame. 1645 __ leave(); 1646 1647 // Remove caller arguments from the stack. 1648 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 1649 __ pop(ecx); 1650 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver 1651 __ push(ecx); 1652 } 1653 1654 // static 1655 void Builtins::Generate_CallOrConstructVarargs(MacroAssembler* masm, 1656 Handle<Code> code) { 1657 // ----------- S t a t e ------------- 1658 // -- edi : target 1659 // -- eax : number of parameters on the stack (not including the receiver) 1660 // -- ebx : arguments list (a FixedArray) 1661 // -- ecx : len (number of elements to from args) 1662 // -- edx : new.target (checked to be constructor or undefined) 1663 // -- esp[0] : return address. 1664 // ----------------------------------- 1665 1666 // We need to preserve eax, edi and ebx. 1667 __ movd(xmm0, edx); 1668 __ movd(xmm1, edi); 1669 __ movd(xmm2, eax); 1670 1671 if (masm->emit_debug_code()) { 1672 // Allow ebx to be a FixedArray, or a FixedDoubleArray if ecx == 0. 1673 Label ok, fail; 1674 __ AssertNotSmi(ebx); 1675 __ mov(edx, FieldOperand(ebx, HeapObject::kMapOffset)); 1676 __ CmpInstanceType(edx, FIXED_ARRAY_TYPE); 1677 __ j(equal, &ok); 1678 __ CmpInstanceType(edx, FIXED_DOUBLE_ARRAY_TYPE); 1679 __ j(not_equal, &fail); 1680 __ cmp(ecx, 0); 1681 __ j(equal, &ok); 1682 // Fall through. 1683 __ bind(&fail); 1684 __ Abort(AbortReason::kOperandIsNotAFixedArray); 1685 1686 __ bind(&ok); 1687 } 1688 1689 // Check for stack overflow. 1690 { 1691 // Check the stack for overflow. We are not trying to catch interruptions 1692 // (i.e. debug break and preemption) here, so check the "real stack limit". 1693 Label done; 1694 ExternalReference real_stack_limit = 1695 ExternalReference::address_of_real_stack_limit(masm->isolate()); 1696 __ mov(edx, __ StaticVariable(real_stack_limit)); 1697 // Make edx the space we have left. The stack might already be overflowed 1698 // here which will cause edx to become negative. 1699 __ neg(edx); 1700 __ add(edx, esp); 1701 __ sar(edx, kPointerSizeLog2); 1702 // Check if the arguments will overflow the stack. 1703 __ cmp(edx, ecx); 1704 __ j(greater, &done, Label::kNear); // Signed comparison. 1705 __ TailCallRuntime(Runtime::kThrowStackOverflow); 1706 __ bind(&done); 1707 } 1708 1709 // Push additional arguments onto the stack. 1710 { 1711 __ PopReturnAddressTo(edx); 1712 __ Move(eax, Immediate(0)); 1713 Label done, push, loop; 1714 __ bind(&loop); 1715 __ cmp(eax, ecx); 1716 __ j(equal, &done, Label::kNear); 1717 // Turn the hole into undefined as we go. 1718 __ mov(edi, 1719 FieldOperand(ebx, eax, times_pointer_size, FixedArray::kHeaderSize)); 1720 __ CompareRoot(edi, Heap::kTheHoleValueRootIndex); 1721 __ j(not_equal, &push, Label::kNear); 1722 __ LoadRoot(edi, Heap::kUndefinedValueRootIndex); 1723 __ bind(&push); 1724 __ Push(edi); 1725 __ inc(eax); 1726 __ jmp(&loop); 1727 __ bind(&done); 1728 __ PushReturnAddressFrom(edx); 1729 } 1730 1731 // Restore eax, edi and edx. 1732 __ movd(eax, xmm2); 1733 __ movd(edi, xmm1); 1734 __ movd(edx, xmm0); 1735 1736 // Compute the actual parameter count. 1737 __ add(eax, ecx); 1738 1739 // Tail-call to the actual Call or Construct builtin. 1740 __ Jump(code, RelocInfo::CODE_TARGET); 1741 } 1742 1743 // static 1744 void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm, 1745 CallOrConstructMode mode, 1746 Handle<Code> code) { 1747 // ----------- S t a t e ------------- 1748 // -- eax : the number of arguments (not including the receiver) 1749 // -- edi : the target to call (can be any Object) 1750 // -- edx : the new target (for [[Construct]] calls) 1751 // -- ecx : start index (to support rest parameters) 1752 // ----------------------------------- 1753 1754 // Check if new.target has a [[Construct]] internal method. 1755 if (mode == CallOrConstructMode::kConstruct) { 1756 Label new_target_constructor, new_target_not_constructor; 1757 __ JumpIfSmi(edx, &new_target_not_constructor, Label::kNear); 1758 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 1759 __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), 1760 Immediate(Map::IsConstructorBit::kMask)); 1761 __ j(not_zero, &new_target_constructor, Label::kNear); 1762 __ bind(&new_target_not_constructor); 1763 { 1764 FrameScope scope(masm, StackFrame::MANUAL); 1765 __ EnterFrame(StackFrame::INTERNAL); 1766 __ Push(edx); 1767 __ CallRuntime(Runtime::kThrowNotConstructor); 1768 } 1769 __ bind(&new_target_constructor); 1770 } 1771 1772 // Preserve new.target (in case of [[Construct]]). 1773 __ movd(xmm0, edx); 1774 1775 // Check if we have an arguments adaptor frame below the function frame. 1776 Label arguments_adaptor, arguments_done; 1777 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 1778 __ cmp(Operand(ebx, CommonFrameConstants::kContextOrFrameTypeOffset), 1779 Immediate(StackFrame::TypeToMarker(StackFrame::ARGUMENTS_ADAPTOR))); 1780 __ j(equal, &arguments_adaptor, Label::kNear); 1781 { 1782 __ mov(edx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 1783 __ mov(edx, FieldOperand(edx, JSFunction::kSharedFunctionInfoOffset)); 1784 __ movzx_w(edx, FieldOperand( 1785 edx, SharedFunctionInfo::kFormalParameterCountOffset)); 1786 __ mov(ebx, ebp); 1787 } 1788 __ jmp(&arguments_done, Label::kNear); 1789 __ bind(&arguments_adaptor); 1790 { 1791 // Just load the length from the ArgumentsAdaptorFrame. 1792 __ mov(edx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 1793 __ SmiUntag(edx); 1794 } 1795 __ bind(&arguments_done); 1796 1797 Label stack_done; 1798 __ sub(edx, ecx); 1799 __ j(less_equal, &stack_done); 1800 { 1801 // Check for stack overflow. 1802 { 1803 // Check the stack for overflow. We are not trying to catch interruptions 1804 // (i.e. debug break and preemption) here, so check the "real stack 1805 // limit". 1806 Label done; 1807 __ LoadRoot(ecx, Heap::kRealStackLimitRootIndex); 1808 // Make ecx the space we have left. The stack might already be 1809 // overflowed here which will cause ecx to become negative. 1810 __ neg(ecx); 1811 __ add(ecx, esp); 1812 __ sar(ecx, kPointerSizeLog2); 1813 // Check if the arguments will overflow the stack. 1814 __ cmp(ecx, edx); 1815 __ j(greater, &done, Label::kNear); // Signed comparison. 1816 __ TailCallRuntime(Runtime::kThrowStackOverflow); 1817 __ bind(&done); 1818 } 1819 1820 // Forward the arguments from the caller frame. 1821 { 1822 Label loop; 1823 __ add(eax, edx); 1824 __ PopReturnAddressTo(ecx); 1825 __ bind(&loop); 1826 { 1827 __ Push(Operand(ebx, edx, times_pointer_size, 1 * kPointerSize)); 1828 __ dec(edx); 1829 __ j(not_zero, &loop); 1830 } 1831 __ PushReturnAddressFrom(ecx); 1832 } 1833 } 1834 __ bind(&stack_done); 1835 1836 // Restore new.target (in case of [[Construct]]). 1837 __ movd(edx, xmm0); 1838 1839 // Tail-call to the {code} handler. 1840 __ Jump(code, RelocInfo::CODE_TARGET); 1841 } 1842 1843 // static 1844 void Builtins::Generate_CallFunction(MacroAssembler* masm, 1845 ConvertReceiverMode mode) { 1846 // ----------- S t a t e ------------- 1847 // -- eax : the number of arguments (not including the receiver) 1848 // -- edi : the function to call (checked to be a JSFunction) 1849 // ----------------------------------- 1850 __ AssertFunction(edi); 1851 1852 // See ES6 section 9.2.1 [[Call]] ( thisArgument, argumentsList) 1853 // Check that the function is not a "classConstructor". 1854 Label class_constructor; 1855 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 1856 __ test(FieldOperand(edx, SharedFunctionInfo::kFlagsOffset), 1857 Immediate(SharedFunctionInfo::IsClassConstructorBit::kMask)); 1858 __ j(not_zero, &class_constructor); 1859 1860 // Enter the context of the function; ToObject has to run in the function 1861 // context, and we also need to take the global proxy from the function 1862 // context in case of conversion. 1863 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); 1864 // We need to convert the receiver for non-native sloppy mode functions. 1865 Label done_convert; 1866 __ test(FieldOperand(edx, SharedFunctionInfo::kFlagsOffset), 1867 Immediate(SharedFunctionInfo::IsNativeBit::kMask | 1868 SharedFunctionInfo::IsStrictBit::kMask)); 1869 __ j(not_zero, &done_convert); 1870 { 1871 // ----------- S t a t e ------------- 1872 // -- eax : the number of arguments (not including the receiver) 1873 // -- edx : the shared function info. 1874 // -- edi : the function to call (checked to be a JSFunction) 1875 // -- esi : the function context. 1876 // ----------------------------------- 1877 1878 if (mode == ConvertReceiverMode::kNullOrUndefined) { 1879 // Patch receiver to global proxy. 1880 __ LoadGlobalProxy(ecx); 1881 } else { 1882 Label convert_to_object, convert_receiver; 1883 __ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize)); 1884 __ JumpIfSmi(ecx, &convert_to_object, Label::kNear); 1885 STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); 1886 __ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx); 1887 __ j(above_equal, &done_convert); 1888 if (mode != ConvertReceiverMode::kNotNullOrUndefined) { 1889 Label convert_global_proxy; 1890 __ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex, 1891 &convert_global_proxy, Label::kNear); 1892 __ JumpIfNotRoot(ecx, Heap::kNullValueRootIndex, &convert_to_object, 1893 Label::kNear); 1894 __ bind(&convert_global_proxy); 1895 { 1896 // Patch receiver to global proxy. 1897 __ LoadGlobalProxy(ecx); 1898 } 1899 __ jmp(&convert_receiver); 1900 } 1901 __ bind(&convert_to_object); 1902 { 1903 // Convert receiver using ToObject. 1904 // TODO(bmeurer): Inline the allocation here to avoid building the frame 1905 // in the fast case? (fall back to AllocateInNewSpace?) 1906 FrameScope scope(masm, StackFrame::INTERNAL); 1907 __ SmiTag(eax); 1908 __ Push(eax); 1909 __ Push(edi); 1910 __ mov(eax, ecx); 1911 __ Push(esi); 1912 __ Call(BUILTIN_CODE(masm->isolate(), ToObject), 1913 RelocInfo::CODE_TARGET); 1914 __ Pop(esi); 1915 __ mov(ecx, eax); 1916 __ Pop(edi); 1917 __ Pop(eax); 1918 __ SmiUntag(eax); 1919 } 1920 __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 1921 __ bind(&convert_receiver); 1922 } 1923 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ecx); 1924 } 1925 __ bind(&done_convert); 1926 1927 // ----------- S t a t e ------------- 1928 // -- eax : the number of arguments (not including the receiver) 1929 // -- edx : the shared function info. 1930 // -- edi : the function to call (checked to be a JSFunction) 1931 // -- esi : the function context. 1932 // ----------------------------------- 1933 1934 __ movzx_w( 1935 ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset)); 1936 ParameterCount actual(eax); 1937 ParameterCount expected(ebx); 1938 __ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION); 1939 // The function is a "classConstructor", need to raise an exception. 1940 __ bind(&class_constructor); 1941 { 1942 FrameScope frame(masm, StackFrame::INTERNAL); 1943 __ push(edi); 1944 __ CallRuntime(Runtime::kThrowConstructorNonCallableError); 1945 } 1946 } 1947 1948 namespace { 1949 1950 void Generate_PushBoundArguments(MacroAssembler* masm) { 1951 // ----------- S t a t e ------------- 1952 // -- eax : the number of arguments (not including the receiver) 1953 // -- edx : new.target (only in case of [[Construct]]) 1954 // -- edi : target (checked to be a JSBoundFunction) 1955 // ----------------------------------- 1956 1957 // Load [[BoundArguments]] into ecx and length of that into ebx. 1958 Label no_bound_arguments; 1959 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset)); 1960 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); 1961 __ SmiUntag(ebx); 1962 __ test(ebx, ebx); 1963 __ j(zero, &no_bound_arguments); 1964 { 1965 // ----------- S t a t e ------------- 1966 // -- eax : the number of arguments (not including the receiver) 1967 // -- edx : new.target (only in case of [[Construct]]) 1968 // -- edi : target (checked to be a JSBoundFunction) 1969 // -- ecx : the [[BoundArguments]] (implemented as FixedArray) 1970 // -- ebx : the number of [[BoundArguments]] 1971 // ----------------------------------- 1972 1973 // Reserve stack space for the [[BoundArguments]]. 1974 { 1975 Label done; 1976 __ lea(ecx, Operand(ebx, times_pointer_size, 0)); 1977 __ sub(esp, ecx); 1978 // Check the stack for overflow. We are not trying to catch interruptions 1979 // (i.e. debug break and preemption) here, so check the "real stack 1980 // limit". 1981 __ CompareRoot(esp, ecx, Heap::kRealStackLimitRootIndex); 1982 __ j(greater, &done, Label::kNear); // Signed comparison. 1983 // Restore the stack pointer. 1984 __ lea(esp, Operand(esp, ebx, times_pointer_size, 0)); 1985 { 1986 FrameScope scope(masm, StackFrame::MANUAL); 1987 __ EnterFrame(StackFrame::INTERNAL); 1988 __ CallRuntime(Runtime::kThrowStackOverflow); 1989 } 1990 __ bind(&done); 1991 } 1992 1993 // Adjust effective number of arguments to include return address. 1994 __ inc(eax); 1995 1996 // Relocate arguments and return address down the stack. 1997 { 1998 Label loop; 1999 __ Set(ecx, 0); 2000 __ lea(ebx, Operand(esp, ebx, times_pointer_size, 0)); 2001 __ bind(&loop); 2002 __ movd(xmm0, Operand(ebx, ecx, times_pointer_size, 0)); 2003 __ movd(Operand(esp, ecx, times_pointer_size, 0), xmm0); 2004 __ inc(ecx); 2005 __ cmp(ecx, eax); 2006 __ j(less, &loop); 2007 } 2008 2009 // Copy [[BoundArguments]] to the stack (below the arguments). 2010 { 2011 Label loop; 2012 __ mov(ecx, FieldOperand(edi, JSBoundFunction::kBoundArgumentsOffset)); 2013 __ mov(ebx, FieldOperand(ecx, FixedArray::kLengthOffset)); 2014 __ SmiUntag(ebx); 2015 __ bind(&loop); 2016 __ dec(ebx); 2017 __ movd(xmm0, FieldOperand(ecx, ebx, times_pointer_size, 2018 FixedArray::kHeaderSize)); 2019 __ movd(Operand(esp, eax, times_pointer_size, 0), xmm0); 2020 __ lea(eax, Operand(eax, 1)); 2021 __ j(greater, &loop); 2022 } 2023 2024 // Adjust effective number of arguments (eax contains the number of 2025 // arguments from the call plus return address plus the number of 2026 // [[BoundArguments]]), so we need to subtract one for the return address. 2027 __ dec(eax); 2028 } 2029 __ bind(&no_bound_arguments); 2030 } 2031 2032 } // namespace 2033 2034 // static 2035 void Builtins::Generate_CallBoundFunctionImpl(MacroAssembler* masm) { 2036 // ----------- S t a t e ------------- 2037 // -- eax : the number of arguments (not including the receiver) 2038 // -- edi : the function to call (checked to be a JSBoundFunction) 2039 // ----------------------------------- 2040 __ AssertBoundFunction(edi); 2041 2042 // Patch the receiver to [[BoundThis]]. 2043 __ mov(ebx, FieldOperand(edi, JSBoundFunction::kBoundThisOffset)); 2044 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), ebx); 2045 2046 // Push the [[BoundArguments]] onto the stack. 2047 Generate_PushBoundArguments(masm); 2048 2049 // Call the [[BoundTargetFunction]] via the Call builtin. 2050 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); 2051 __ Jump(BUILTIN_CODE(masm->isolate(), Call_ReceiverIsAny), 2052 RelocInfo::CODE_TARGET); 2053 } 2054 2055 // static 2056 void Builtins::Generate_Call(MacroAssembler* masm, ConvertReceiverMode mode) { 2057 // ----------- S t a t e ------------- 2058 // -- eax : the number of arguments (not including the receiver) 2059 // -- edi : the target to call (can be any Object). 2060 // ----------------------------------- 2061 2062 Label non_callable, non_function, non_smi; 2063 __ JumpIfSmi(edi, &non_callable); 2064 __ bind(&non_smi); 2065 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 2066 __ j(equal, masm->isolate()->builtins()->CallFunction(mode), 2067 RelocInfo::CODE_TARGET); 2068 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE); 2069 __ j(equal, BUILTIN_CODE(masm->isolate(), CallBoundFunction), 2070 RelocInfo::CODE_TARGET); 2071 2072 // Check if target is a proxy and call CallProxy external builtin 2073 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 2074 Immediate(Map::IsCallableBit::kMask)); 2075 __ j(zero, &non_callable); 2076 2077 // Call CallProxy external builtin 2078 __ CmpInstanceType(ecx, JS_PROXY_TYPE); 2079 __ j(not_equal, &non_function); 2080 __ Jump(BUILTIN_CODE(masm->isolate(), CallProxy), RelocInfo::CODE_TARGET); 2081 2082 // 2. Call to something else, which might have a [[Call]] internal method (if 2083 // not we raise an exception). 2084 __ bind(&non_function); 2085 // Overwrite the original receiver with the (original) target. 2086 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi); 2087 // Let the "call_as_function_delegate" take care of the rest. 2088 __ LoadGlobalFunction(Context::CALL_AS_FUNCTION_DELEGATE_INDEX, edi); 2089 __ Jump(masm->isolate()->builtins()->CallFunction( 2090 ConvertReceiverMode::kNotNullOrUndefined), 2091 RelocInfo::CODE_TARGET); 2092 2093 // 3. Call to something that is not callable. 2094 __ bind(&non_callable); 2095 { 2096 FrameScope scope(masm, StackFrame::INTERNAL); 2097 __ Push(edi); 2098 __ CallRuntime(Runtime::kThrowCalledNonCallable); 2099 } 2100 } 2101 2102 // static 2103 void Builtins::Generate_ConstructFunction(MacroAssembler* masm) { 2104 // ----------- S t a t e ------------- 2105 // -- eax : the number of arguments (not including the receiver) 2106 // -- edx : the new target (checked to be a constructor) 2107 // -- edi : the constructor to call (checked to be a JSFunction) 2108 // ----------------------------------- 2109 __ AssertConstructor(edi); 2110 __ AssertFunction(edi); 2111 2112 // Calling convention for function specific ConstructStubs require 2113 // ebx to contain either an AllocationSite or undefined. 2114 __ LoadRoot(ebx, Heap::kUndefinedValueRootIndex); 2115 2116 Label call_generic_stub; 2117 2118 // Jump to JSBuiltinsConstructStub or JSConstructStubGeneric. 2119 __ mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 2120 __ test(FieldOperand(ecx, SharedFunctionInfo::kFlagsOffset), 2121 Immediate(SharedFunctionInfo::ConstructAsBuiltinBit::kMask)); 2122 __ j(zero, &call_generic_stub, Label::kNear); 2123 2124 __ Jump(BUILTIN_CODE(masm->isolate(), JSBuiltinsConstructStub), 2125 RelocInfo::CODE_TARGET); 2126 2127 __ bind(&call_generic_stub); 2128 __ Jump(BUILTIN_CODE(masm->isolate(), JSConstructStubGeneric), 2129 RelocInfo::CODE_TARGET); 2130 } 2131 2132 // static 2133 void Builtins::Generate_ConstructBoundFunction(MacroAssembler* masm) { 2134 // ----------- S t a t e ------------- 2135 // -- eax : the number of arguments (not including the receiver) 2136 // -- edx : the new target (checked to be a constructor) 2137 // -- edi : the constructor to call (checked to be a JSBoundFunction) 2138 // ----------------------------------- 2139 __ AssertConstructor(edi); 2140 __ AssertBoundFunction(edi); 2141 2142 // Push the [[BoundArguments]] onto the stack. 2143 Generate_PushBoundArguments(masm); 2144 2145 // Patch new.target to [[BoundTargetFunction]] if new.target equals target. 2146 { 2147 Label done; 2148 __ cmp(edi, edx); 2149 __ j(not_equal, &done, Label::kNear); 2150 __ mov(edx, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); 2151 __ bind(&done); 2152 } 2153 2154 // Construct the [[BoundTargetFunction]] via the Construct builtin. 2155 __ mov(edi, FieldOperand(edi, JSBoundFunction::kBoundTargetFunctionOffset)); 2156 __ Jump(BUILTIN_CODE(masm->isolate(), Construct), RelocInfo::CODE_TARGET); 2157 } 2158 2159 // static 2160 void 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, non_proxy; 2170 __ JumpIfSmi(edi, &non_constructor, Label::kNear); 2171 2172 // Check if target has a [[Construct]] internal method. 2173 __ mov(ecx, FieldOperand(edi, HeapObject::kMapOffset)); 2174 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 2175 Immediate(Map::IsConstructorBit::kMask)); 2176 __ j(zero, &non_constructor, Label::kNear); 2177 2178 // Dispatch based on instance type. 2179 __ CmpInstanceType(ecx, JS_FUNCTION_TYPE); 2180 __ j(equal, BUILTIN_CODE(masm->isolate(), ConstructFunction), 2181 RelocInfo::CODE_TARGET); 2182 2183 // Only dispatch to bound functions after checking whether they are 2184 // constructors. 2185 __ CmpInstanceType(ecx, JS_BOUND_FUNCTION_TYPE); 2186 __ j(equal, BUILTIN_CODE(masm->isolate(), ConstructBoundFunction), 2187 RelocInfo::CODE_TARGET); 2188 2189 // Only dispatch to proxies after checking whether they are constructors. 2190 __ CmpInstanceType(ecx, JS_PROXY_TYPE); 2191 __ j(not_equal, &non_proxy); 2192 __ Jump(BUILTIN_CODE(masm->isolate(), ConstructProxy), 2193 RelocInfo::CODE_TARGET); 2194 2195 // Called Construct on an exotic Object with a [[Construct]] internal method. 2196 __ bind(&non_proxy); 2197 { 2198 // Overwrite the original receiver with the (original) target. 2199 __ mov(Operand(esp, eax, times_pointer_size, kPointerSize), edi); 2200 // Let the "call_as_constructor_delegate" take care of the rest. 2201 __ LoadGlobalFunction(Context::CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, edi); 2202 __ Jump(masm->isolate()->builtins()->CallFunction(), 2203 RelocInfo::CODE_TARGET); 2204 } 2205 2206 // Called Construct on an Object that doesn't have a [[Construct]] internal 2207 // method. 2208 __ bind(&non_constructor); 2209 __ Jump(BUILTIN_CODE(masm->isolate(), ConstructedNonConstructable), 2210 RelocInfo::CODE_TARGET); 2211 } 2212 2213 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { 2214 // ----------- S t a t e ------------- 2215 // -- eax : actual number of arguments 2216 // -- ebx : expected number of arguments 2217 // -- edx : new target (passed through to callee) 2218 // -- edi : function (passed through to callee) 2219 // ----------------------------------- 2220 2221 Label invoke, dont_adapt_arguments, stack_overflow; 2222 __ IncrementCounter(masm->isolate()->counters()->arguments_adaptors(), 1); 2223 2224 Label enough, too_few; 2225 __ cmp(ebx, SharedFunctionInfo::kDontAdaptArgumentsSentinel); 2226 __ j(equal, &dont_adapt_arguments); 2227 __ cmp(eax, ebx); 2228 __ j(less, &too_few); 2229 2230 { // Enough parameters: Actual >= expected. 2231 __ bind(&enough); 2232 EnterArgumentsAdaptorFrame(masm); 2233 // edi is used as a scratch register. It should be restored from the frame 2234 // when needed. 2235 Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow); 2236 2237 // Copy receiver and all expected arguments. 2238 const int offset = StandardFrameConstants::kCallerSPOffset; 2239 __ lea(edi, Operand(ebp, eax, times_4, offset)); 2240 __ mov(eax, -1); // account for receiver 2241 2242 Label copy; 2243 __ bind(©); 2244 __ inc(eax); 2245 __ push(Operand(edi, 0)); 2246 __ sub(edi, Immediate(kPointerSize)); 2247 __ cmp(eax, ebx); 2248 __ j(less, ©); 2249 // eax now contains the expected number of arguments. 2250 __ jmp(&invoke); 2251 } 2252 2253 { // Too few parameters: Actual < expected. 2254 __ bind(&too_few); 2255 EnterArgumentsAdaptorFrame(masm); 2256 // edi is used as a scratch register. It should be restored from the frame 2257 // when needed. 2258 Generate_StackOverflowCheck(masm, ebx, ecx, edi, &stack_overflow); 2259 2260 // Remember expected arguments in ecx. 2261 __ mov(ecx, ebx); 2262 2263 // Copy receiver and all actual arguments. 2264 const int offset = StandardFrameConstants::kCallerSPOffset; 2265 __ lea(edi, Operand(ebp, eax, times_4, offset)); 2266 // ebx = expected - actual. 2267 __ sub(ebx, eax); 2268 // eax = -actual - 1 2269 __ neg(eax); 2270 __ sub(eax, Immediate(1)); 2271 2272 Label copy; 2273 __ bind(©); 2274 __ inc(eax); 2275 __ push(Operand(edi, 0)); 2276 __ sub(edi, Immediate(kPointerSize)); 2277 __ test(eax, eax); 2278 __ j(not_zero, ©); 2279 2280 // Fill remaining expected arguments with undefined values. 2281 Label fill; 2282 __ bind(&fill); 2283 __ inc(eax); 2284 __ push(Immediate(masm->isolate()->factory()->undefined_value())); 2285 __ cmp(eax, ebx); 2286 __ j(less, &fill); 2287 2288 // Restore expected arguments. 2289 __ mov(eax, ecx); 2290 } 2291 2292 // Call the entry point. 2293 __ bind(&invoke); 2294 // Restore function pointer. 2295 __ mov(edi, Operand(ebp, ArgumentsAdaptorFrameConstants::kFunctionOffset)); 2296 // eax : expected number of arguments 2297 // edx : new target (passed through to callee) 2298 // edi : function (passed through to callee) 2299 static_assert(kJavaScriptCallCodeStartRegister == ecx, "ABI mismatch"); 2300 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeOffset)); 2301 __ add(ecx, Immediate(Code::kHeaderSize - kHeapObjectTag)); 2302 __ call(ecx); 2303 2304 // Store offset of return address for deoptimizer. 2305 masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset()); 2306 2307 // Leave frame and return. 2308 LeaveArgumentsAdaptorFrame(masm); 2309 __ ret(0); 2310 2311 // ------------------------------------------- 2312 // Dont adapt arguments. 2313 // ------------------------------------------- 2314 __ bind(&dont_adapt_arguments); 2315 static_assert(kJavaScriptCallCodeStartRegister == ecx, "ABI mismatch"); 2316 __ mov(ecx, FieldOperand(edi, JSFunction::kCodeOffset)); 2317 __ add(ecx, Immediate(Code::kHeaderSize - kHeapObjectTag)); 2318 __ jmp(ecx); 2319 2320 __ bind(&stack_overflow); 2321 { 2322 FrameScope frame(masm, StackFrame::MANUAL); 2323 __ CallRuntime(Runtime::kThrowStackOverflow); 2324 __ int3(); 2325 } 2326 } 2327 2328 static void Generate_OnStackReplacementHelper(MacroAssembler* masm, 2329 bool has_handler_frame) { 2330 // Lookup the function in the JavaScript frame. 2331 if (has_handler_frame) { 2332 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 2333 __ mov(eax, Operand(eax, JavaScriptFrameConstants::kFunctionOffset)); 2334 } else { 2335 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 2336 } 2337 2338 { 2339 FrameScope scope(masm, StackFrame::INTERNAL); 2340 // Pass function as argument. 2341 __ push(eax); 2342 __ CallRuntime(Runtime::kCompileForOnStackReplacement); 2343 } 2344 2345 Label skip; 2346 // If the code object is null, just return to the caller. 2347 __ cmp(eax, Immediate(0)); 2348 __ j(not_equal, &skip, Label::kNear); 2349 __ ret(0); 2350 2351 __ bind(&skip); 2352 2353 // Drop any potential handler frame that is be sitting on top of the actual 2354 // JavaScript frame. This is the case then OSR is triggered from bytecode. 2355 if (has_handler_frame) { 2356 __ leave(); 2357 } 2358 2359 // Load deoptimization data from the code object. 2360 __ mov(ebx, Operand(eax, Code::kDeoptimizationDataOffset - kHeapObjectTag)); 2361 2362 // Load the OSR entrypoint offset from the deoptimization data. 2363 __ mov(ebx, Operand(ebx, FixedArray::OffsetOfElementAt( 2364 DeoptimizationData::kOsrPcOffsetIndex) - 2365 kHeapObjectTag)); 2366 __ SmiUntag(ebx); 2367 2368 // Compute the target address = code_obj + header_size + osr_offset 2369 __ lea(eax, Operand(eax, ebx, times_1, Code::kHeaderSize - kHeapObjectTag)); 2370 2371 // Overwrite the return address on the stack. 2372 __ mov(Operand(esp, 0), eax); 2373 2374 // And "return" to the OSR entry point of the function. 2375 __ ret(0); 2376 } 2377 2378 void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) { 2379 Generate_OnStackReplacementHelper(masm, false); 2380 } 2381 2382 void Builtins::Generate_InterpreterOnStackReplacement(MacroAssembler* masm) { 2383 Generate_OnStackReplacementHelper(masm, true); 2384 } 2385 2386 void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) { 2387 // The function index was put in edi by the jump table trampoline. 2388 // Convert to Smi for the runtime call. 2389 __ SmiTag(edi); 2390 { 2391 HardAbortScope hard_abort(masm); // Avoid calls to Abort. 2392 FrameScope scope(masm, StackFrame::WASM_COMPILE_LAZY); 2393 2394 // Save all parameter registers (see wasm-linkage.cc). They might be 2395 // overwritten in the runtime call below. We don't have any callee-saved 2396 // registers in wasm, so no need to store anything else. 2397 static_assert(WasmCompileLazyFrameConstants::kNumberOfSavedGpParamRegs == 2398 arraysize(wasm::kGpParamRegisters), 2399 "frame size mismatch"); 2400 for (Register reg : wasm::kGpParamRegisters) { 2401 __ Push(reg); 2402 } 2403 static_assert(WasmCompileLazyFrameConstants::kNumberOfSavedFpParamRegs == 2404 arraysize(wasm::kFpParamRegisters), 2405 "frame size mismatch"); 2406 __ sub(esp, Immediate(kSimd128Size * arraysize(wasm::kFpParamRegisters))); 2407 int offset = 0; 2408 for (DoubleRegister reg : wasm::kFpParamRegisters) { 2409 __ movdqu(Operand(esp, offset), reg); 2410 offset += kSimd128Size; 2411 } 2412 2413 // Push the WASM instance as an explicit argument to WasmCompileLazy. 2414 __ Push(kWasmInstanceRegister); 2415 // Push the function index as second argument. 2416 __ Push(edi); 2417 // Load the correct CEntry builtin from the instance object. 2418 __ mov(ecx, FieldOperand(kWasmInstanceRegister, 2419 WasmInstanceObject::kCEntryStubOffset)); 2420 // Initialize the JavaScript context with 0. CEntry will use it to 2421 // set the current context on the isolate. 2422 __ Move(kContextRegister, Smi::kZero); 2423 __ CallRuntimeWithCEntry(Runtime::kWasmCompileLazy, ecx); 2424 // The entrypoint address is the return value. 2425 __ mov(edi, kReturnRegister0); 2426 2427 // Restore registers. 2428 for (DoubleRegister reg : base::Reversed(wasm::kFpParamRegisters)) { 2429 offset -= kSimd128Size; 2430 __ movdqu(reg, Operand(esp, offset)); 2431 } 2432 DCHECK_EQ(0, offset); 2433 __ add(esp, Immediate(kSimd128Size * arraysize(wasm::kFpParamRegisters))); 2434 for (Register reg : base::Reversed(wasm::kGpParamRegisters)) { 2435 __ Pop(reg); 2436 } 2437 } 2438 // Finally, jump to the entrypoint. 2439 __ jmp(edi); 2440 } 2441 2442 void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size, 2443 SaveFPRegsMode save_doubles, ArgvMode argv_mode, 2444 bool builtin_exit_frame) { 2445 // eax: number of arguments including receiver 2446 // edx: pointer to C function 2447 // ebp: frame pointer (restored after C call) 2448 // esp: stack pointer (restored after C call) 2449 // esi: current context (C callee-saved) 2450 // edi: JS function of the caller (C callee-saved) 2451 // 2452 // If argv_mode == kArgvInRegister: 2453 // ecx: pointer to the first argument 2454 2455 STATIC_ASSERT(eax == kRuntimeCallArgCountRegister); 2456 STATIC_ASSERT(ecx == kRuntimeCallArgvRegister); 2457 STATIC_ASSERT(edx == kRuntimeCallFunctionRegister); 2458 STATIC_ASSERT(esi == kContextRegister); 2459 STATIC_ASSERT(edi == kJSFunctionRegister); 2460 2461 DCHECK(!AreAliased(kRuntimeCallArgCountRegister, kRuntimeCallArgvRegister, 2462 kRuntimeCallFunctionRegister, kContextRegister, 2463 kJSFunctionRegister, kRootRegister)); 2464 2465 ProfileEntryHookStub::MaybeCallEntryHook(masm); 2466 2467 // Reserve space on the stack for the three arguments passed to the call. If 2468 // result size is greater than can be returned in registers, also reserve 2469 // space for the hidden argument for the result location, and space for the 2470 // result itself. 2471 int arg_stack_space = 3; 2472 2473 // Enter the exit frame that transitions from JavaScript to C++. 2474 if (argv_mode == kArgvInRegister) { 2475 DCHECK(save_doubles == kDontSaveFPRegs); 2476 DCHECK(!builtin_exit_frame); 2477 __ EnterApiExitFrame(arg_stack_space); 2478 2479 // Move argc and argv into the correct registers. 2480 __ mov(esi, ecx); 2481 __ mov(edi, eax); 2482 } else { 2483 __ EnterExitFrame( 2484 arg_stack_space, save_doubles == kSaveFPRegs, 2485 builtin_exit_frame ? StackFrame::BUILTIN_EXIT : StackFrame::EXIT); 2486 } 2487 2488 // edx: pointer to C function 2489 // ebp: frame pointer (restored after C call) 2490 // esp: stack pointer (restored after C call) 2491 // edi: number of arguments including receiver (C callee-saved) 2492 // esi: pointer to the first argument (C callee-saved) 2493 2494 // Result returned in eax, or eax+edx if result size is 2. 2495 2496 // Check stack alignment. 2497 if (FLAG_debug_code) { 2498 __ CheckStackAlignment(); 2499 } 2500 // Call C function. 2501 __ mov(Operand(esp, 0 * kPointerSize), edi); // argc. 2502 __ mov(Operand(esp, 1 * kPointerSize), esi); // argv. 2503 __ mov(Operand(esp, 2 * kPointerSize), 2504 Immediate(ExternalReference::isolate_address(masm->isolate()))); 2505 __ call(kRuntimeCallFunctionRegister); 2506 2507 // Result is in eax or edx:eax - do not destroy these registers! 2508 2509 // Check result for exception sentinel. 2510 Label exception_returned; 2511 __ cmp(eax, masm->isolate()->factory()->exception()); 2512 __ j(equal, &exception_returned); 2513 2514 // Check that there is no pending exception, otherwise we 2515 // should have returned the exception sentinel. 2516 if (FLAG_debug_code) { 2517 __ push(edx); 2518 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value())); 2519 Label okay; 2520 ExternalReference pending_exception_address = ExternalReference::Create( 2521 IsolateAddressId::kPendingExceptionAddress, masm->isolate()); 2522 __ cmp(edx, __ StaticVariable(pending_exception_address)); 2523 // Cannot use check here as it attempts to generate call into runtime. 2524 __ j(equal, &okay, Label::kNear); 2525 __ int3(); 2526 __ bind(&okay); 2527 __ pop(edx); 2528 } 2529 2530 // Exit the JavaScript to C++ exit frame. 2531 __ LeaveExitFrame(save_doubles == kSaveFPRegs, argv_mode == kArgvOnStack); 2532 __ ret(0); 2533 2534 // Handling of exception. 2535 __ bind(&exception_returned); 2536 2537 ExternalReference pending_handler_context_address = ExternalReference::Create( 2538 IsolateAddressId::kPendingHandlerContextAddress, masm->isolate()); 2539 ExternalReference pending_handler_entrypoint_address = 2540 ExternalReference::Create( 2541 IsolateAddressId::kPendingHandlerEntrypointAddress, masm->isolate()); 2542 ExternalReference pending_handler_fp_address = ExternalReference::Create( 2543 IsolateAddressId::kPendingHandlerFPAddress, masm->isolate()); 2544 ExternalReference pending_handler_sp_address = ExternalReference::Create( 2545 IsolateAddressId::kPendingHandlerSPAddress, masm->isolate()); 2546 2547 // Ask the runtime for help to determine the handler. This will set eax to 2548 // contain the current pending exception, don't clobber it. 2549 ExternalReference find_handler = 2550 ExternalReference::Create(Runtime::kUnwindAndFindExceptionHandler); 2551 { 2552 FrameScope scope(masm, StackFrame::MANUAL); 2553 __ PrepareCallCFunction(3, eax); 2554 __ mov(Operand(esp, 0 * kPointerSize), Immediate(0)); // argc. 2555 __ mov(Operand(esp, 1 * kPointerSize), Immediate(0)); // argv. 2556 __ mov(Operand(esp, 2 * kPointerSize), 2557 Immediate(ExternalReference::isolate_address(masm->isolate()))); 2558 __ CallCFunction(find_handler, 3); 2559 } 2560 2561 // Retrieve the handler context, SP and FP. 2562 __ mov(esi, __ StaticVariable(pending_handler_context_address)); 2563 __ mov(esp, __ StaticVariable(pending_handler_sp_address)); 2564 __ mov(ebp, __ StaticVariable(pending_handler_fp_address)); 2565 2566 // If the handler is a JS frame, restore the context to the frame. Note that 2567 // the context will be set to (esi == 0) for non-JS frames. 2568 Label skip; 2569 __ test(esi, esi); 2570 __ j(zero, &skip, Label::kNear); 2571 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); 2572 __ bind(&skip); 2573 2574 // Reset the masking register. This is done independent of the underlying 2575 // feature flag {FLAG_branch_load_poisoning} to make the snapshot work with 2576 // both configurations. It is safe to always do this, because the underlying 2577 // register is caller-saved and can be arbitrarily clobbered. 2578 __ ResetSpeculationPoisonRegister(); 2579 2580 // Compute the handler entry address and jump to it. 2581 __ mov(edi, __ StaticVariable(pending_handler_entrypoint_address)); 2582 __ jmp(edi); 2583 } 2584 2585 void Builtins::Generate_DoubleToI(MacroAssembler* masm) { 2586 Label check_negative, process_64_bits, done; 2587 2588 // Account for return address and saved regs. 2589 const int kArgumentOffset = 4 * kPointerSize; 2590 2591 MemOperand mantissa_operand(MemOperand(esp, kArgumentOffset)); 2592 MemOperand exponent_operand( 2593 MemOperand(esp, kArgumentOffset + kDoubleSize / 2)); 2594 2595 // The result is returned on the stack. 2596 MemOperand return_operand = mantissa_operand; 2597 2598 Register scratch1 = ebx; 2599 2600 // Since we must use ecx for shifts below, use some other register (eax) 2601 // to calculate the result. 2602 Register result_reg = eax; 2603 // Save ecx if it isn't the return register and therefore volatile, or if it 2604 // is the return register, then save the temp register we use in its stead for 2605 // the result. 2606 Register save_reg = eax; 2607 __ push(ecx); 2608 __ push(scratch1); 2609 __ push(save_reg); 2610 2611 __ mov(scratch1, mantissa_operand); 2612 if (CpuFeatures::IsSupported(SSE3)) { 2613 CpuFeatureScope scope(masm, SSE3); 2614 // Load x87 register with heap number. 2615 __ fld_d(mantissa_operand); 2616 } 2617 __ mov(ecx, exponent_operand); 2618 2619 __ and_(ecx, HeapNumber::kExponentMask); 2620 __ shr(ecx, HeapNumber::kExponentShift); 2621 __ lea(result_reg, MemOperand(ecx, -HeapNumber::kExponentBias)); 2622 __ cmp(result_reg, Immediate(HeapNumber::kMantissaBits)); 2623 __ j(below, &process_64_bits); 2624 2625 // Result is entirely in lower 32-bits of mantissa 2626 int delta = HeapNumber::kExponentBias + Double::kPhysicalSignificandSize; 2627 if (CpuFeatures::IsSupported(SSE3)) { 2628 __ fstp(0); 2629 } 2630 __ sub(ecx, Immediate(delta)); 2631 __ xor_(result_reg, result_reg); 2632 __ cmp(ecx, Immediate(31)); 2633 __ j(above, &done); 2634 __ shl_cl(scratch1); 2635 __ jmp(&check_negative); 2636 2637 __ bind(&process_64_bits); 2638 if (CpuFeatures::IsSupported(SSE3)) { 2639 CpuFeatureScope scope(masm, SSE3); 2640 // Reserve space for 64 bit answer. 2641 __ sub(esp, Immediate(kDoubleSize)); // Nolint. 2642 // Do conversion, which cannot fail because we checked the exponent. 2643 __ fisttp_d(Operand(esp, 0)); 2644 __ mov(result_reg, Operand(esp, 0)); // Load low word of answer as result 2645 __ add(esp, Immediate(kDoubleSize)); 2646 __ jmp(&done); 2647 } else { 2648 // Result must be extracted from shifted 32-bit mantissa 2649 __ sub(ecx, Immediate(delta)); 2650 __ neg(ecx); 2651 __ mov(result_reg, exponent_operand); 2652 __ and_(result_reg, 2653 Immediate(static_cast<uint32_t>(Double::kSignificandMask >> 32))); 2654 __ add(result_reg, 2655 Immediate(static_cast<uint32_t>(Double::kHiddenBit >> 32))); 2656 __ shrd_cl(scratch1, result_reg); 2657 __ shr_cl(result_reg); 2658 __ test(ecx, Immediate(32)); 2659 __ cmov(not_equal, scratch1, result_reg); 2660 } 2661 2662 // If the double was negative, negate the integer result. 2663 __ bind(&check_negative); 2664 __ mov(result_reg, scratch1); 2665 __ neg(result_reg); 2666 __ cmp(exponent_operand, Immediate(0)); 2667 __ cmov(greater, result_reg, scratch1); 2668 2669 // Restore registers 2670 __ bind(&done); 2671 __ mov(return_operand, result_reg); 2672 __ pop(save_reg); 2673 __ pop(scratch1); 2674 __ pop(ecx); 2675 __ ret(0); 2676 } 2677 2678 void Builtins::Generate_MathPowInternal(MacroAssembler* masm) { 2679 const Register exponent = eax; 2680 const Register scratch = ecx; 2681 const XMMRegister double_result = xmm3; 2682 const XMMRegister double_base = xmm2; 2683 const XMMRegister double_exponent = xmm1; 2684 const XMMRegister double_scratch = xmm4; 2685 2686 Label call_runtime, done, exponent_not_smi, int_exponent; 2687 2688 // Save 1 in double_result - we need this several times later on. 2689 __ mov(scratch, Immediate(1)); 2690 __ Cvtsi2sd(double_result, scratch); 2691 2692 Label fast_power, try_arithmetic_simplification; 2693 __ DoubleToI(exponent, double_exponent, double_scratch, 2694 &try_arithmetic_simplification, &try_arithmetic_simplification); 2695 __ jmp(&int_exponent); 2696 2697 __ bind(&try_arithmetic_simplification); 2698 // Skip to runtime if possibly NaN (indicated by the indefinite integer). 2699 __ cvttsd2si(exponent, Operand(double_exponent)); 2700 __ cmp(exponent, Immediate(0x1)); 2701 __ j(overflow, &call_runtime); 2702 2703 // Using FPU instructions to calculate power. 2704 Label fast_power_failed; 2705 __ bind(&fast_power); 2706 __ fnclex(); // Clear flags to catch exceptions later. 2707 // Transfer (B)ase and (E)xponent onto the FPU register stack. 2708 __ sub(esp, Immediate(kDoubleSize)); 2709 __ movsd(Operand(esp, 0), double_exponent); 2710 __ fld_d(Operand(esp, 0)); // E 2711 __ movsd(Operand(esp, 0), double_base); 2712 __ fld_d(Operand(esp, 0)); // B, E 2713 2714 // Exponent is in st(1) and base is in st(0) 2715 // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B) 2716 // FYL2X calculates st(1) * log2(st(0)) 2717 __ fyl2x(); // X 2718 __ fld(0); // X, X 2719 __ frndint(); // rnd(X), X 2720 __ fsub(1); // rnd(X), X-rnd(X) 2721 __ fxch(1); // X - rnd(X), rnd(X) 2722 // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1 2723 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X) 2724 __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X) 2725 __ faddp(1); // 2^(X-rnd(X)), rnd(X) 2726 // FSCALE calculates st(0) * 2^st(1) 2727 __ fscale(); // 2^X, rnd(X) 2728 __ fstp(1); // 2^X 2729 // Bail out to runtime in case of exceptions in the status word. 2730 __ fnstsw_ax(); 2731 __ test_b(eax, Immediate(0x5F)); // We check for all but precision exception. 2732 __ j(not_zero, &fast_power_failed, Label::kNear); 2733 __ fstp_d(Operand(esp, 0)); 2734 __ movsd(double_result, Operand(esp, 0)); 2735 __ add(esp, Immediate(kDoubleSize)); 2736 __ jmp(&done); 2737 2738 __ bind(&fast_power_failed); 2739 __ fninit(); 2740 __ add(esp, Immediate(kDoubleSize)); 2741 __ jmp(&call_runtime); 2742 2743 // Calculate power with integer exponent. 2744 __ bind(&int_exponent); 2745 const XMMRegister double_scratch2 = double_exponent; 2746 __ mov(scratch, exponent); // Back up exponent. 2747 __ movsd(double_scratch, double_base); // Back up base. 2748 __ movsd(double_scratch2, double_result); // Load double_exponent with 1. 2749 2750 // Get absolute value of exponent. 2751 Label no_neg, while_true, while_false; 2752 __ test(scratch, scratch); 2753 __ j(positive, &no_neg, Label::kNear); 2754 __ neg(scratch); 2755 __ bind(&no_neg); 2756 2757 __ j(zero, &while_false, Label::kNear); 2758 __ shr(scratch, 1); 2759 // Above condition means CF==0 && ZF==0. This means that the 2760 // bit that has been shifted out is 0 and the result is not 0. 2761 __ j(above, &while_true, Label::kNear); 2762 __ movsd(double_result, double_scratch); 2763 __ j(zero, &while_false, Label::kNear); 2764 2765 __ bind(&while_true); 2766 __ shr(scratch, 1); 2767 __ mulsd(double_scratch, double_scratch); 2768 __ j(above, &while_true, Label::kNear); 2769 __ mulsd(double_result, double_scratch); 2770 __ j(not_zero, &while_true); 2771 2772 __ bind(&while_false); 2773 // scratch has the original value of the exponent - if the exponent is 2774 // negative, return 1/result. 2775 __ test(exponent, exponent); 2776 __ j(positive, &done); 2777 __ divsd(double_scratch2, double_result); 2778 __ movsd(double_result, double_scratch2); 2779 // Test whether result is zero. Bail out to check for subnormal result. 2780 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. 2781 __ xorps(double_scratch2, double_scratch2); 2782 __ ucomisd(double_scratch2, double_result); // Result cannot be NaN. 2783 // double_exponent aliased as double_scratch2 has already been overwritten 2784 // and may not have contained the exponent value in the first place when the 2785 // exponent is a smi. We reset it with exponent value before bailing out. 2786 __ j(not_equal, &done); 2787 __ Cvtsi2sd(double_exponent, exponent); 2788 2789 // Returning or bailing out. 2790 __ bind(&call_runtime); 2791 { 2792 AllowExternalCallThatCantCauseGC scope(masm); 2793 __ PrepareCallCFunction(4, scratch); 2794 __ movsd(Operand(esp, 0 * kDoubleSize), double_base); 2795 __ movsd(Operand(esp, 1 * kDoubleSize), double_exponent); 2796 __ CallCFunction(ExternalReference::power_double_double_function(), 4); 2797 } 2798 // Return value is in st(0) on ia32. 2799 // Store it into the (fixed) result register. 2800 __ sub(esp, Immediate(kDoubleSize)); 2801 __ fstp_d(Operand(esp, 0)); 2802 __ movsd(double_result, Operand(esp, 0)); 2803 __ add(esp, Immediate(kDoubleSize)); 2804 2805 __ bind(&done); 2806 __ ret(0); 2807 } 2808 2809 namespace { 2810 2811 void GenerateInternalArrayConstructorCase(MacroAssembler* masm, 2812 ElementsKind kind) { 2813 Label not_zero_case, not_one_case; 2814 Label normal_sequence; 2815 2816 __ test(eax, eax); 2817 __ j(not_zero, ¬_zero_case); 2818 __ Jump(CodeFactory::InternalArrayNoArgumentConstructor(masm->isolate(), kind) 2819 .code(), 2820 RelocInfo::CODE_TARGET); 2821 2822 __ bind(¬_zero_case); 2823 __ cmp(eax, 1); 2824 __ j(greater, ¬_one_case); 2825 2826 if (IsFastPackedElementsKind(kind)) { 2827 // We might need to create a holey array 2828 // look at the first argument 2829 __ mov(ecx, Operand(esp, kPointerSize)); 2830 __ test(ecx, ecx); 2831 __ j(zero, &normal_sequence); 2832 2833 __ Jump(CodeFactory::InternalArraySingleArgumentConstructor( 2834 masm->isolate(), GetHoleyElementsKind(kind)) 2835 .code(), 2836 RelocInfo::CODE_TARGET); 2837 } 2838 2839 __ bind(&normal_sequence); 2840 __ Jump( 2841 CodeFactory::InternalArraySingleArgumentConstructor(masm->isolate(), kind) 2842 .code(), 2843 RelocInfo::CODE_TARGET); 2844 2845 __ bind(¬_one_case); 2846 // TODO(v8:6666): When rewriting ia32 ASM builtins to not clobber the 2847 // kRootRegister ebx, this useless move can be removed. 2848 __ Move(kJavaScriptCallExtraArg1Register, ebx); 2849 Handle<Code> code = BUILTIN_CODE(masm->isolate(), ArrayNArgumentsConstructor); 2850 __ Jump(code, RelocInfo::CODE_TARGET); 2851 } 2852 2853 } // namespace 2854 2855 void Builtins::Generate_InternalArrayConstructorImpl(MacroAssembler* masm) { 2856 // ----------- S t a t e ------------- 2857 // -- eax : argc 2858 // -- edi : constructor 2859 // -- esp[0] : return address 2860 // -- esp[4] : last argument 2861 // ----------------------------------- 2862 2863 if (FLAG_debug_code) { 2864 // The array construct code is only set for the global and natives 2865 // builtin Array functions which always have maps. 2866 2867 // Initial map for the builtin Array function should be a map. 2868 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 2869 // Will both indicate a nullptr and a Smi. 2870 __ test(ecx, Immediate(kSmiTagMask)); 2871 __ Assert(not_zero, AbortReason::kUnexpectedInitialMapForArrayFunction); 2872 __ CmpObjectType(ecx, MAP_TYPE, ecx); 2873 __ Assert(equal, AbortReason::kUnexpectedInitialMapForArrayFunction); 2874 } 2875 2876 // Figure out the right elements kind 2877 __ mov(ecx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); 2878 2879 // Load the map's "bit field 2" into |result|. We only need the first byte, 2880 // but the following masking takes care of that anyway. 2881 __ mov(ecx, FieldOperand(ecx, Map::kBitField2Offset)); 2882 // Retrieve elements_kind from bit field 2. 2883 __ DecodeField<Map::ElementsKindBits>(ecx); 2884 2885 if (FLAG_debug_code) { 2886 Label done; 2887 __ cmp(ecx, Immediate(PACKED_ELEMENTS)); 2888 __ j(equal, &done); 2889 __ cmp(ecx, Immediate(HOLEY_ELEMENTS)); 2890 __ Assert( 2891 equal, 2892 AbortReason::kInvalidElementsKindForInternalArrayOrInternalPackedArray); 2893 __ bind(&done); 2894 } 2895 2896 Label fast_elements_case; 2897 __ cmp(ecx, Immediate(PACKED_ELEMENTS)); 2898 __ j(equal, &fast_elements_case); 2899 GenerateInternalArrayConstructorCase(masm, HOLEY_ELEMENTS); 2900 2901 __ bind(&fast_elements_case); 2902 GenerateInternalArrayConstructorCase(masm, PACKED_ELEMENTS); 2903 } 2904 2905 #undef __ 2906 2907 } // namespace internal 2908 } // namespace v8 2909 2910 #endif // V8_TARGET_ARCH_IA32 2911