OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
308 int3(); | 308 int3(); |
309 } | 309 } |
310 | 310 |
311 | 311 |
312 void MacroAssembler::CallStub(CodeStub* stub) { | 312 void MacroAssembler::CallStub(CodeStub* stub) { |
313 ASSERT(allow_stub_calls()); // calls are not allowed in some stubs | 313 ASSERT(allow_stub_calls()); // calls are not allowed in some stubs |
314 Call(stub->GetCode(), RelocInfo::CODE_TARGET); | 314 Call(stub->GetCode(), RelocInfo::CODE_TARGET); |
315 } | 315 } |
316 | 316 |
317 | 317 |
318 Object* MacroAssembler::TryCallStub(CodeStub* stub) { | 318 MaybeObject* MacroAssembler::TryCallStub(CodeStub* stub) { |
319 ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs. | 319 ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs. |
320 Object* result = stub->TryGetCode(); | 320 MaybeObject* result = stub->TryGetCode(); |
321 if (!result->IsFailure()) { | 321 if (!result->IsFailure()) { |
322 call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET); | 322 call(Handle<Code>(Code::cast(result->ToObjectUnchecked())), |
| 323 RelocInfo::CODE_TARGET); |
323 } | 324 } |
324 return result; | 325 return result; |
325 } | 326 } |
326 | 327 |
327 | 328 |
328 void MacroAssembler::TailCallStub(CodeStub* stub) { | 329 void MacroAssembler::TailCallStub(CodeStub* stub) { |
329 ASSERT(allow_stub_calls()); // calls are not allowed in some stubs | 330 ASSERT(allow_stub_calls()); // calls are not allowed in some stubs |
330 Jump(stub->GetCode(), RelocInfo::CODE_TARGET); | 331 Jump(stub->GetCode(), RelocInfo::CODE_TARGET); |
331 } | 332 } |
332 | 333 |
333 | 334 |
334 Object* MacroAssembler::TryTailCallStub(CodeStub* stub) { | 335 MaybeObject* MacroAssembler::TryTailCallStub(CodeStub* stub) { |
335 ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs. | 336 ASSERT(allow_stub_calls()); // Calls are not allowed in some stubs. |
336 Object* result = stub->TryGetCode(); | 337 MaybeObject* result = stub->TryGetCode(); |
337 if (!result->IsFailure()) { | 338 if (!result->IsFailure()) { |
338 jmp(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET); | 339 jmp(Handle<Code>(Code::cast(result->ToObjectUnchecked())), |
| 340 RelocInfo::CODE_TARGET); |
339 } | 341 } |
340 return result; | 342 return result; |
341 } | 343 } |
342 | 344 |
343 | 345 |
344 void MacroAssembler::StubReturn(int argc) { | 346 void MacroAssembler::StubReturn(int argc) { |
345 ASSERT(argc >= 1 && generating_stub()); | 347 ASSERT(argc >= 1 && generating_stub()); |
346 ret((argc - 1) * kPointerSize); | 348 ret((argc - 1) * kPointerSize); |
347 } | 349 } |
348 | 350 |
(...skipping 23 matching lines...) Expand all Loading... |
372 // there is no difference in using either key. | 374 // there is no difference in using either key. |
373 Integer32ToSmi(index, hash); | 375 Integer32ToSmi(index, hash); |
374 } | 376 } |
375 | 377 |
376 | 378 |
377 void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { | 379 void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { |
378 CallRuntime(Runtime::FunctionForId(id), num_arguments); | 380 CallRuntime(Runtime::FunctionForId(id), num_arguments); |
379 } | 381 } |
380 | 382 |
381 | 383 |
382 Object* MacroAssembler::TryCallRuntime(Runtime::FunctionId id, | 384 MaybeObject* MacroAssembler::TryCallRuntime(Runtime::FunctionId id, |
383 int num_arguments) { | 385 int num_arguments) { |
384 return TryCallRuntime(Runtime::FunctionForId(id), num_arguments); | 386 return TryCallRuntime(Runtime::FunctionForId(id), num_arguments); |
385 } | 387 } |
386 | 388 |
387 | 389 |
388 void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { | 390 void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { |
389 // If the expected number of arguments of the runtime function is | 391 // If the expected number of arguments of the runtime function is |
390 // constant, we check that the actual number of arguments match the | 392 // constant, we check that the actual number of arguments match the |
391 // expectation. | 393 // expectation. |
392 if (f->nargs >= 0 && f->nargs != num_arguments) { | 394 if (f->nargs >= 0 && f->nargs != num_arguments) { |
393 IllegalOperation(num_arguments); | 395 IllegalOperation(num_arguments); |
394 return; | 396 return; |
395 } | 397 } |
396 | 398 |
397 // TODO(1236192): Most runtime routines don't need the number of | 399 // TODO(1236192): Most runtime routines don't need the number of |
398 // arguments passed in because it is constant. At some point we | 400 // arguments passed in because it is constant. At some point we |
399 // should remove this need and make the runtime routine entry code | 401 // should remove this need and make the runtime routine entry code |
400 // smarter. | 402 // smarter. |
401 Set(rax, num_arguments); | 403 Set(rax, num_arguments); |
402 movq(rbx, ExternalReference(f)); | 404 movq(rbx, ExternalReference(f)); |
403 CEntryStub ces(f->result_size); | 405 CEntryStub ces(f->result_size); |
404 CallStub(&ces); | 406 CallStub(&ces); |
405 } | 407 } |
406 | 408 |
407 | 409 |
408 Object* MacroAssembler::TryCallRuntime(Runtime::Function* f, | 410 MaybeObject* MacroAssembler::TryCallRuntime(Runtime::Function* f, |
409 int num_arguments) { | 411 int num_arguments) { |
410 if (f->nargs >= 0 && f->nargs != num_arguments) { | 412 if (f->nargs >= 0 && f->nargs != num_arguments) { |
411 IllegalOperation(num_arguments); | 413 IllegalOperation(num_arguments); |
412 // Since we did not call the stub, there was no allocation failure. | 414 // Since we did not call the stub, there was no allocation failure. |
413 // Return some non-failure object. | 415 // Return some non-failure object. |
414 return Heap::undefined_value(); | 416 return Heap::undefined_value(); |
415 } | 417 } |
416 | 418 |
417 // TODO(1236192): Most runtime routines don't need the number of | 419 // TODO(1236192): Most runtime routines don't need the number of |
418 // arguments passed in because it is constant. At some point we | 420 // arguments passed in because it is constant. At some point we |
419 // should remove this need and make the runtime routine entry code | 421 // should remove this need and make the runtime routine entry code |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 | 464 |
463 | 465 |
464 static int Offset(ExternalReference ref0, ExternalReference ref1) { | 466 static int Offset(ExternalReference ref0, ExternalReference ref1) { |
465 int64_t offset = (ref0.address() - ref1.address()); | 467 int64_t offset = (ref0.address() - ref1.address()); |
466 // Check that fits into int. | 468 // Check that fits into int. |
467 ASSERT(static_cast<int>(offset) == offset); | 469 ASSERT(static_cast<int>(offset) == offset); |
468 return static_cast<int>(offset); | 470 return static_cast<int>(offset); |
469 } | 471 } |
470 | 472 |
471 | 473 |
472 void MacroAssembler::PushHandleScope(Register scratch) { | 474 void MacroAssembler::PrepareCallApiFunction(int stack_space) { |
473 ExternalReference extensions_address = | 475 EnterApiExitFrame(stack_space, 0); |
474 ExternalReference::handle_scope_extensions_address(); | |
475 const int kExtensionsOffset = 0; | |
476 const int kNextOffset = Offset( | |
477 ExternalReference::handle_scope_next_address(), | |
478 extensions_address); | |
479 const int kLimitOffset = Offset( | |
480 ExternalReference::handle_scope_limit_address(), | |
481 extensions_address); | |
482 | |
483 // Push the number of extensions, smi-tagged so the gc will ignore it. | |
484 movq(kScratchRegister, extensions_address); | |
485 movq(scratch, Operand(kScratchRegister, kExtensionsOffset)); | |
486 movq(Operand(kScratchRegister, kExtensionsOffset), Immediate(0)); | |
487 Integer32ToSmi(scratch, scratch); | |
488 push(scratch); | |
489 // Push next and limit pointers which will be wordsize aligned and | |
490 // hence automatically smi tagged. | |
491 push(Operand(kScratchRegister, kNextOffset)); | |
492 push(Operand(kScratchRegister, kLimitOffset)); | |
493 } | 476 } |
494 | 477 |
495 | 478 |
496 Object* MacroAssembler::PopHandleScopeHelper(Register saved, | 479 void MacroAssembler::CallApiFunctionAndReturn(ApiFunction* function) { |
497 Register scratch, | 480 Label empty_result; |
498 bool gc_allowed) { | 481 Label prologue; |
499 ExternalReference extensions_address = | 482 Label promote_scheduled_exception; |
500 ExternalReference::handle_scope_extensions_address(); | 483 Label delete_allocated_handles; |
501 const int kExtensionsOffset = 0; | 484 Label leave_exit_frame; |
502 const int kNextOffset = Offset( | 485 Label write_back; |
503 ExternalReference::handle_scope_next_address(), | 486 |
504 extensions_address); | 487 ExternalReference next_address = |
| 488 ExternalReference::handle_scope_next_address(); |
| 489 const int kNextOffset = 0; |
505 const int kLimitOffset = Offset( | 490 const int kLimitOffset = Offset( |
506 ExternalReference::handle_scope_limit_address(), | 491 ExternalReference::handle_scope_limit_address(), |
507 extensions_address); | 492 next_address); |
| 493 const int kLevelOffset = Offset( |
| 494 ExternalReference::handle_scope_level_address(), |
| 495 next_address); |
| 496 ExternalReference scheduled_exception_address = |
| 497 ExternalReference::scheduled_exception_address(); |
508 | 498 |
509 Object* result = NULL; | 499 // Allocate HandleScope in callee-save registers. |
510 Label write_back; | 500 Register prev_next_address_reg = r14; |
511 movq(kScratchRegister, extensions_address); | 501 Register prev_limit_reg = rbx; |
512 cmpq(Operand(kScratchRegister, kExtensionsOffset), Immediate(0)); | 502 Register base_reg = kSmiConstantRegister; |
513 j(equal, &write_back); | 503 movq(base_reg, next_address); |
514 push(saved); | 504 movq(prev_next_address_reg, Operand(base_reg, kNextOffset)); |
515 if (gc_allowed) { | 505 movq(prev_limit_reg, Operand(base_reg, kLimitOffset)); |
516 CallRuntime(Runtime::kDeleteHandleScopeExtensions, 0); | 506 addl(Operand(base_reg, kLevelOffset), Immediate(1)); |
517 } else { | 507 // Call the api function! |
518 result = TryCallRuntime(Runtime::kDeleteHandleScopeExtensions, 0); | 508 movq(rax, |
519 if (result->IsFailure()) return result; | 509 reinterpret_cast<int64_t>(function->address()), |
520 } | 510 RelocInfo::RUNTIME_ENTRY); |
521 pop(saved); | 511 call(rax); |
522 movq(kScratchRegister, extensions_address); | |
523 | 512 |
524 bind(&write_back); | 513 #ifdef _WIN64 |
525 pop(Operand(kScratchRegister, kLimitOffset)); | 514 // rax keeps a pointer to v8::Handle, unpack it. |
526 pop(Operand(kScratchRegister, kNextOffset)); | 515 movq(rax, Operand(rax, 0)); |
527 pop(scratch); | 516 #endif |
528 SmiToInteger32(scratch, scratch); | 517 // Check if the result handle holds 0. |
529 movq(Operand(kScratchRegister, kExtensionsOffset), scratch); | 518 testq(rax, rax); |
| 519 j(zero, &empty_result); |
| 520 // It was non-zero. Dereference to get the result value. |
| 521 movq(rax, Operand(rax, 0)); |
| 522 bind(&prologue); |
530 | 523 |
531 return result; | 524 // No more valid handles (the result handle was the last one). Restore |
| 525 // previous handle scope. |
| 526 subl(Operand(base_reg, kLevelOffset), Immediate(1)); |
| 527 movq(Operand(base_reg, kNextOffset), prev_next_address_reg); |
| 528 cmpq(prev_limit_reg, Operand(base_reg, kLimitOffset)); |
| 529 j(not_equal, &delete_allocated_handles); |
| 530 bind(&leave_exit_frame); |
| 531 InitializeSmiConstantRegister(); |
| 532 |
| 533 // Check if the function scheduled an exception. |
| 534 movq(rsi, scheduled_exception_address); |
| 535 Cmp(Operand(rsi, 0), Factory::the_hole_value()); |
| 536 j(not_equal, &promote_scheduled_exception); |
| 537 |
| 538 LeaveExitFrame(); |
| 539 ret(0); |
| 540 |
| 541 bind(&promote_scheduled_exception); |
| 542 TailCallRuntime(Runtime::kPromoteScheduledException, 0, 1); |
| 543 |
| 544 bind(&empty_result); |
| 545 // It was zero; the result is undefined. |
| 546 Move(rax, Factory::undefined_value()); |
| 547 jmp(&prologue); |
| 548 |
| 549 // HandleScope limit has changed. Delete allocated extensions. |
| 550 bind(&delete_allocated_handles); |
| 551 movq(Operand(base_reg, kLimitOffset), prev_limit_reg); |
| 552 movq(prev_limit_reg, rax); |
| 553 movq(rax, ExternalReference::delete_handle_scope_extensions()); |
| 554 call(rax); |
| 555 movq(rax, prev_limit_reg); |
| 556 jmp(&leave_exit_frame); |
532 } | 557 } |
533 | 558 |
534 | 559 |
535 void MacroAssembler::PopHandleScope(Register saved, Register scratch) { | |
536 PopHandleScopeHelper(saved, scratch, true); | |
537 } | |
538 | |
539 | |
540 Object* MacroAssembler::TryPopHandleScope(Register saved, Register scratch) { | |
541 return PopHandleScopeHelper(saved, scratch, false); | |
542 } | |
543 | |
544 | |
545 void MacroAssembler::JumpToExternalReference(const ExternalReference& ext, | 560 void MacroAssembler::JumpToExternalReference(const ExternalReference& ext, |
546 int result_size) { | 561 int result_size) { |
547 // Set the entry point and jump to the C entry runtime stub. | 562 // Set the entry point and jump to the C entry runtime stub. |
548 movq(rbx, ext); | 563 movq(rbx, ext); |
549 CEntryStub ces(result_size); | 564 CEntryStub ces(result_size); |
550 jmp(ces.GetCode(), RelocInfo::CODE_TARGET); | 565 jmp(ces.GetCode(), RelocInfo::CODE_TARGET); |
551 } | 566 } |
552 | 567 |
553 | 568 |
554 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) { | 569 void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id, InvokeFlag flag) { |
(...skipping 1329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1884 } | 1899 } |
1885 } | 1900 } |
1886 | 1901 |
1887 | 1902 |
1888 void MacroAssembler::AllocateInNewSpace(int object_size, | 1903 void MacroAssembler::AllocateInNewSpace(int object_size, |
1889 Register result, | 1904 Register result, |
1890 Register result_end, | 1905 Register result_end, |
1891 Register scratch, | 1906 Register scratch, |
1892 Label* gc_required, | 1907 Label* gc_required, |
1893 AllocationFlags flags) { | 1908 AllocationFlags flags) { |
| 1909 if (!FLAG_inline_new) { |
| 1910 if (FLAG_debug_code) { |
| 1911 // Trash the registers to simulate an allocation failure. |
| 1912 movl(result, Immediate(0x7091)); |
| 1913 if (result_end.is_valid()) { |
| 1914 movl(result_end, Immediate(0x7191)); |
| 1915 } |
| 1916 if (scratch.is_valid()) { |
| 1917 movl(scratch, Immediate(0x7291)); |
| 1918 } |
| 1919 } |
| 1920 jmp(gc_required); |
| 1921 return; |
| 1922 } |
1894 ASSERT(!result.is(result_end)); | 1923 ASSERT(!result.is(result_end)); |
1895 | 1924 |
1896 // Load address of new object into result. | 1925 // Load address of new object into result. |
1897 LoadAllocationTopHelper(result, result_end, scratch, flags); | 1926 LoadAllocationTopHelper(result, result_end, scratch, flags); |
1898 | 1927 |
1899 // Calculate new top and bail out if new space is exhausted. | 1928 // Calculate new top and bail out if new space is exhausted. |
1900 ExternalReference new_space_allocation_limit = | 1929 ExternalReference new_space_allocation_limit = |
1901 ExternalReference::new_space_allocation_limit_address(); | 1930 ExternalReference::new_space_allocation_limit_address(); |
1902 | 1931 |
1903 Register top_reg = result_end.is_valid() ? result_end : result; | 1932 Register top_reg = result_end.is_valid() ? result_end : result; |
(...skipping 24 matching lines...) Expand all Loading... |
1928 | 1957 |
1929 | 1958 |
1930 void MacroAssembler::AllocateInNewSpace(int header_size, | 1959 void MacroAssembler::AllocateInNewSpace(int header_size, |
1931 ScaleFactor element_size, | 1960 ScaleFactor element_size, |
1932 Register element_count, | 1961 Register element_count, |
1933 Register result, | 1962 Register result, |
1934 Register result_end, | 1963 Register result_end, |
1935 Register scratch, | 1964 Register scratch, |
1936 Label* gc_required, | 1965 Label* gc_required, |
1937 AllocationFlags flags) { | 1966 AllocationFlags flags) { |
| 1967 if (!FLAG_inline_new) { |
| 1968 if (FLAG_debug_code) { |
| 1969 // Trash the registers to simulate an allocation failure. |
| 1970 movl(result, Immediate(0x7091)); |
| 1971 movl(result_end, Immediate(0x7191)); |
| 1972 if (scratch.is_valid()) { |
| 1973 movl(scratch, Immediate(0x7291)); |
| 1974 } |
| 1975 // Register element_count is not modified by the function. |
| 1976 } |
| 1977 jmp(gc_required); |
| 1978 return; |
| 1979 } |
1938 ASSERT(!result.is(result_end)); | 1980 ASSERT(!result.is(result_end)); |
1939 | 1981 |
1940 // Load address of new object into result. | 1982 // Load address of new object into result. |
1941 LoadAllocationTopHelper(result, result_end, scratch, flags); | 1983 LoadAllocationTopHelper(result, result_end, scratch, flags); |
1942 | 1984 |
1943 // Calculate new top and bail out if new space is exhausted. | 1985 // Calculate new top and bail out if new space is exhausted. |
1944 ExternalReference new_space_allocation_limit = | 1986 ExternalReference new_space_allocation_limit = |
1945 ExternalReference::new_space_allocation_limit_address(); | 1987 ExternalReference::new_space_allocation_limit_address(); |
1946 lea(result_end, Operand(result, element_count, element_size, header_size)); | 1988 lea(result_end, Operand(result, element_count, element_size, header_size)); |
1947 movq(kScratchRegister, new_space_allocation_limit); | 1989 movq(kScratchRegister, new_space_allocation_limit); |
1948 cmpq(result_end, Operand(kScratchRegister, 0)); | 1990 cmpq(result_end, Operand(kScratchRegister, 0)); |
1949 j(above, gc_required); | 1991 j(above, gc_required); |
1950 | 1992 |
1951 // Update allocation top. | 1993 // Update allocation top. |
1952 UpdateAllocationTopHelper(result_end, scratch); | 1994 UpdateAllocationTopHelper(result_end, scratch); |
1953 | 1995 |
1954 // Tag the result if requested. | 1996 // Tag the result if requested. |
1955 if ((flags & TAG_OBJECT) != 0) { | 1997 if ((flags & TAG_OBJECT) != 0) { |
1956 addq(result, Immediate(kHeapObjectTag)); | 1998 addq(result, Immediate(kHeapObjectTag)); |
1957 } | 1999 } |
1958 } | 2000 } |
1959 | 2001 |
1960 | 2002 |
1961 void MacroAssembler::AllocateInNewSpace(Register object_size, | 2003 void MacroAssembler::AllocateInNewSpace(Register object_size, |
1962 Register result, | 2004 Register result, |
1963 Register result_end, | 2005 Register result_end, |
1964 Register scratch, | 2006 Register scratch, |
1965 Label* gc_required, | 2007 Label* gc_required, |
1966 AllocationFlags flags) { | 2008 AllocationFlags flags) { |
| 2009 if (!FLAG_inline_new) { |
| 2010 if (FLAG_debug_code) { |
| 2011 // Trash the registers to simulate an allocation failure. |
| 2012 movl(result, Immediate(0x7091)); |
| 2013 movl(result_end, Immediate(0x7191)); |
| 2014 if (scratch.is_valid()) { |
| 2015 movl(scratch, Immediate(0x7291)); |
| 2016 } |
| 2017 // object_size is left unchanged by this function. |
| 2018 } |
| 2019 jmp(gc_required); |
| 2020 return; |
| 2021 } |
| 2022 ASSERT(!result.is(result_end)); |
| 2023 |
1967 // Load address of new object into result. | 2024 // Load address of new object into result. |
1968 LoadAllocationTopHelper(result, result_end, scratch, flags); | 2025 LoadAllocationTopHelper(result, result_end, scratch, flags); |
1969 | 2026 |
1970 // Calculate new top and bail out if new space is exhausted. | 2027 // Calculate new top and bail out if new space is exhausted. |
1971 ExternalReference new_space_allocation_limit = | 2028 ExternalReference new_space_allocation_limit = |
1972 ExternalReference::new_space_allocation_limit_address(); | 2029 ExternalReference::new_space_allocation_limit_address(); |
1973 if (!object_size.is(result_end)) { | 2030 if (!object_size.is(result_end)) { |
1974 movq(result_end, object_size); | 2031 movq(result_end, object_size); |
1975 } | 2032 } |
1976 addq(result_end, result); | 2033 addq(result_end, result); |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2223 CPU::FlushICache(address_, size_); | 2280 CPU::FlushICache(address_, size_); |
2224 | 2281 |
2225 // Check that the code was patched as expected. | 2282 // Check that the code was patched as expected. |
2226 ASSERT(masm_.pc_ == address_ + size_); | 2283 ASSERT(masm_.pc_ == address_ + size_); |
2227 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); | 2284 ASSERT(masm_.reloc_info_writer.pos() == address_ + size_ + Assembler::kGap); |
2228 } | 2285 } |
2229 | 2286 |
2230 } } // namespace v8::internal | 2287 } } // namespace v8::internal |
2231 | 2288 |
2232 #endif // V8_TARGET_ARCH_X64 | 2289 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |