1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #if V8_TARGET_ARCH_IA32 31 32 #include "codegen.h" 33 #include "heap.h" 34 #include "macro-assembler.h" 35 36 namespace v8 { 37 namespace internal { 38 39 40 // ------------------------------------------------------------------------- 41 // Platform-specific RuntimeCallHelper functions. 42 43 void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const { 44 masm->EnterFrame(StackFrame::INTERNAL); 45 ASSERT(!masm->has_frame()); 46 masm->set_has_frame(true); 47 } 48 49 50 void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { 51 masm->LeaveFrame(StackFrame::INTERNAL); 52 ASSERT(masm->has_frame()); 53 masm->set_has_frame(false); 54 } 55 56 57 #define __ masm. 58 59 60 UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) { 61 size_t actual_size; 62 // Allocate buffer in executable space. 63 byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, 64 &actual_size, 65 true)); 66 if (buffer == NULL) { 67 // Fallback to library function if function cannot be created. 68 switch (type) { 69 case TranscendentalCache::SIN: return &sin; 70 case TranscendentalCache::COS: return &cos; 71 case TranscendentalCache::TAN: return &tan; 72 case TranscendentalCache::LOG: return &log; 73 default: UNIMPLEMENTED(); 74 } 75 } 76 77 MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); 78 // esp[1 * kPointerSize]: raw double input 79 // esp[0 * kPointerSize]: return address 80 // Move double input into registers. 81 82 __ push(ebx); 83 __ push(edx); 84 __ push(edi); 85 __ fld_d(Operand(esp, 4 * kPointerSize)); 86 __ mov(ebx, Operand(esp, 4 * kPointerSize)); 87 __ mov(edx, Operand(esp, 5 * kPointerSize)); 88 TranscendentalCacheStub::GenerateOperation(&masm, type); 89 // The return value is expected to be on ST(0) of the FPU stack. 90 __ pop(edi); 91 __ pop(edx); 92 __ pop(ebx); 93 __ Ret(); 94 95 CodeDesc desc; 96 masm.GetCode(&desc); 97 ASSERT(!RelocInfo::RequiresRelocation(desc)); 98 99 CPU::FlushICache(buffer, actual_size); 100 OS::ProtectCode(buffer, actual_size); 101 return FUNCTION_CAST<UnaryMathFunction>(buffer); 102 } 103 104 105 UnaryMathFunction CreateExpFunction() { 106 if (!CpuFeatures::IsSupported(SSE2)) return &exp; 107 if (!FLAG_fast_math) return &exp; 108 size_t actual_size; 109 byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true)); 110 if (buffer == NULL) return &exp; 111 ExternalReference::InitializeMathExpData(); 112 113 MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); 114 // esp[1 * kPointerSize]: raw double input 115 // esp[0 * kPointerSize]: return address 116 { 117 CpuFeatureScope use_sse2(&masm, SSE2); 118 XMMRegister input = xmm1; 119 XMMRegister result = xmm2; 120 __ movdbl(input, Operand(esp, 1 * kPointerSize)); 121 __ push(eax); 122 __ push(ebx); 123 124 MathExpGenerator::EmitMathExp(&masm, input, result, xmm0, eax, ebx); 125 126 __ pop(ebx); 127 __ pop(eax); 128 __ movdbl(Operand(esp, 1 * kPointerSize), result); 129 __ fld_d(Operand(esp, 1 * kPointerSize)); 130 __ Ret(); 131 } 132 133 CodeDesc desc; 134 masm.GetCode(&desc); 135 ASSERT(!RelocInfo::RequiresRelocation(desc)); 136 137 CPU::FlushICache(buffer, actual_size); 138 OS::ProtectCode(buffer, actual_size); 139 return FUNCTION_CAST<UnaryMathFunction>(buffer); 140 } 141 142 143 UnaryMathFunction CreateSqrtFunction() { 144 size_t actual_size; 145 // Allocate buffer in executable space. 146 byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, 147 &actual_size, 148 true)); 149 // If SSE2 is not available, we can use libc's implementation to ensure 150 // consistency since code by fullcodegen's calls into runtime in that case. 151 if (buffer == NULL || !CpuFeatures::IsSupported(SSE2)) return &sqrt; 152 MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); 153 // esp[1 * kPointerSize]: raw double input 154 // esp[0 * kPointerSize]: return address 155 // Move double input into registers. 156 { 157 CpuFeatureScope use_sse2(&masm, SSE2); 158 __ movdbl(xmm0, Operand(esp, 1 * kPointerSize)); 159 __ sqrtsd(xmm0, xmm0); 160 __ movdbl(Operand(esp, 1 * kPointerSize), xmm0); 161 // Load result into floating point register as return value. 162 __ fld_d(Operand(esp, 1 * kPointerSize)); 163 __ Ret(); 164 } 165 166 CodeDesc desc; 167 masm.GetCode(&desc); 168 ASSERT(!RelocInfo::RequiresRelocation(desc)); 169 170 CPU::FlushICache(buffer, actual_size); 171 OS::ProtectCode(buffer, actual_size); 172 return FUNCTION_CAST<UnaryMathFunction>(buffer); 173 } 174 175 176 // Helper functions for CreateMemMoveFunction. 177 #undef __ 178 #define __ ACCESS_MASM(masm) 179 180 // Keep around global pointers to these objects so that Valgrind won't complain. 181 static size_t* medium_handlers = NULL; 182 static size_t* small_handlers = NULL; 183 184 185 enum Direction { FORWARD, BACKWARD }; 186 enum Alignment { MOVE_ALIGNED, MOVE_UNALIGNED }; 187 188 // Expects registers: 189 // esi - source, aligned if alignment == ALIGNED 190 // edi - destination, always aligned 191 // ecx - count (copy size in bytes) 192 // edx - loop count (number of 64 byte chunks) 193 void MemMoveEmitMainLoop(MacroAssembler* masm, 194 Label* move_last_15, 195 Direction direction, 196 Alignment alignment) { 197 Register src = esi; 198 Register dst = edi; 199 Register count = ecx; 200 Register loop_count = edx; 201 Label loop, move_last_31, move_last_63; 202 __ cmp(loop_count, 0); 203 __ j(equal, &move_last_63); 204 __ bind(&loop); 205 // Main loop. Copy in 64 byte chunks. 206 if (direction == BACKWARD) __ sub(src, Immediate(0x40)); 207 __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00)); 208 __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10)); 209 __ movdq(alignment == MOVE_ALIGNED, xmm2, Operand(src, 0x20)); 210 __ movdq(alignment == MOVE_ALIGNED, xmm3, Operand(src, 0x30)); 211 if (direction == FORWARD) __ add(src, Immediate(0x40)); 212 if (direction == BACKWARD) __ sub(dst, Immediate(0x40)); 213 __ movdqa(Operand(dst, 0x00), xmm0); 214 __ movdqa(Operand(dst, 0x10), xmm1); 215 __ movdqa(Operand(dst, 0x20), xmm2); 216 __ movdqa(Operand(dst, 0x30), xmm3); 217 if (direction == FORWARD) __ add(dst, Immediate(0x40)); 218 __ dec(loop_count); 219 __ j(not_zero, &loop); 220 // At most 63 bytes left to copy. 221 __ bind(&move_last_63); 222 __ test(count, Immediate(0x20)); 223 __ j(zero, &move_last_31); 224 if (direction == BACKWARD) __ sub(src, Immediate(0x20)); 225 __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0x00)); 226 __ movdq(alignment == MOVE_ALIGNED, xmm1, Operand(src, 0x10)); 227 if (direction == FORWARD) __ add(src, Immediate(0x20)); 228 if (direction == BACKWARD) __ sub(dst, Immediate(0x20)); 229 __ movdqa(Operand(dst, 0x00), xmm0); 230 __ movdqa(Operand(dst, 0x10), xmm1); 231 if (direction == FORWARD) __ add(dst, Immediate(0x20)); 232 // At most 31 bytes left to copy. 233 __ bind(&move_last_31); 234 __ test(count, Immediate(0x10)); 235 __ j(zero, move_last_15); 236 if (direction == BACKWARD) __ sub(src, Immediate(0x10)); 237 __ movdq(alignment == MOVE_ALIGNED, xmm0, Operand(src, 0)); 238 if (direction == FORWARD) __ add(src, Immediate(0x10)); 239 if (direction == BACKWARD) __ sub(dst, Immediate(0x10)); 240 __ movdqa(Operand(dst, 0), xmm0); 241 if (direction == FORWARD) __ add(dst, Immediate(0x10)); 242 } 243 244 245 void MemMoveEmitPopAndReturn(MacroAssembler* masm) { 246 __ pop(esi); 247 __ pop(edi); 248 __ ret(0); 249 } 250 251 252 #undef __ 253 #define __ masm. 254 255 256 OS::MemMoveFunction CreateMemMoveFunction() { 257 size_t actual_size; 258 // Allocate buffer in executable space. 259 byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true)); 260 if (buffer == NULL) return NULL; 261 MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size)); 262 263 // Generated code is put into a fixed, unmovable buffer, and not into 264 // the V8 heap. We can't, and don't, refer to any relocatable addresses 265 // (e.g. the JavaScript nan-object). 266 267 // 32-bit C declaration function calls pass arguments on stack. 268 269 // Stack layout: 270 // esp[12]: Third argument, size. 271 // esp[8]: Second argument, source pointer. 272 // esp[4]: First argument, destination pointer. 273 // esp[0]: return address 274 275 const int kDestinationOffset = 1 * kPointerSize; 276 const int kSourceOffset = 2 * kPointerSize; 277 const int kSizeOffset = 3 * kPointerSize; 278 279 // When copying up to this many bytes, use special "small" handlers. 280 const size_t kSmallCopySize = 8; 281 // When copying up to this many bytes, use special "medium" handlers. 282 const size_t kMediumCopySize = 63; 283 // When non-overlapping region of src and dst is less than this, 284 // use a more careful implementation (slightly slower). 285 const size_t kMinMoveDistance = 16; 286 // Note that these values are dictated by the implementation below, 287 // do not just change them and hope things will work! 288 289 int stack_offset = 0; // Update if we change the stack height. 290 291 Label backward, backward_much_overlap; 292 Label forward_much_overlap, small_size, medium_size, pop_and_return; 293 __ push(edi); 294 __ push(esi); 295 stack_offset += 2 * kPointerSize; 296 Register dst = edi; 297 Register src = esi; 298 Register count = ecx; 299 Register loop_count = edx; 300 __ mov(dst, Operand(esp, stack_offset + kDestinationOffset)); 301 __ mov(src, Operand(esp, stack_offset + kSourceOffset)); 302 __ mov(count, Operand(esp, stack_offset + kSizeOffset)); 303 304 __ cmp(dst, src); 305 __ j(equal, &pop_and_return); 306 307 if (CpuFeatures::IsSupported(SSE2)) { 308 CpuFeatureScope sse2_scope(&masm, SSE2); 309 __ prefetch(Operand(src, 0), 1); 310 __ cmp(count, kSmallCopySize); 311 __ j(below_equal, &small_size); 312 __ cmp(count, kMediumCopySize); 313 __ j(below_equal, &medium_size); 314 __ cmp(dst, src); 315 __ j(above, &backward); 316 317 { 318 // |dst| is a lower address than |src|. Copy front-to-back. 319 Label unaligned_source, move_last_15, skip_last_move; 320 __ mov(eax, src); 321 __ sub(eax, dst); 322 __ cmp(eax, kMinMoveDistance); 323 __ j(below, &forward_much_overlap); 324 // Copy first 16 bytes. 325 __ movdqu(xmm0, Operand(src, 0)); 326 __ movdqu(Operand(dst, 0), xmm0); 327 // Determine distance to alignment: 16 - (dst & 0xF). 328 __ mov(edx, dst); 329 __ and_(edx, 0xF); 330 __ neg(edx); 331 __ add(edx, Immediate(16)); 332 __ add(dst, edx); 333 __ add(src, edx); 334 __ sub(count, edx); 335 // dst is now aligned. Main copy loop. 336 __ mov(loop_count, count); 337 __ shr(loop_count, 6); 338 // Check if src is also aligned. 339 __ test(src, Immediate(0xF)); 340 __ j(not_zero, &unaligned_source); 341 // Copy loop for aligned source and destination. 342 MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_ALIGNED); 343 // At most 15 bytes to copy. Copy 16 bytes at end of string. 344 __ bind(&move_last_15); 345 __ and_(count, 0xF); 346 __ j(zero, &skip_last_move, Label::kNear); 347 __ movdqu(xmm0, Operand(src, count, times_1, -0x10)); 348 __ movdqu(Operand(dst, count, times_1, -0x10), xmm0); 349 __ bind(&skip_last_move); 350 MemMoveEmitPopAndReturn(&masm); 351 352 // Copy loop for unaligned source and aligned destination. 353 __ bind(&unaligned_source); 354 MemMoveEmitMainLoop(&masm, &move_last_15, FORWARD, MOVE_UNALIGNED); 355 __ jmp(&move_last_15); 356 357 // Less than kMinMoveDistance offset between dst and src. 358 Label loop_until_aligned, last_15_much_overlap; 359 __ bind(&loop_until_aligned); 360 __ mov_b(eax, Operand(src, 0)); 361 __ inc(src); 362 __ mov_b(Operand(dst, 0), eax); 363 __ inc(dst); 364 __ dec(count); 365 __ bind(&forward_much_overlap); // Entry point into this block. 366 __ test(dst, Immediate(0xF)); 367 __ j(not_zero, &loop_until_aligned); 368 // dst is now aligned, src can't be. Main copy loop. 369 __ mov(loop_count, count); 370 __ shr(loop_count, 6); 371 MemMoveEmitMainLoop(&masm, &last_15_much_overlap, 372 FORWARD, MOVE_UNALIGNED); 373 __ bind(&last_15_much_overlap); 374 __ and_(count, 0xF); 375 __ j(zero, &pop_and_return); 376 __ cmp(count, kSmallCopySize); 377 __ j(below_equal, &small_size); 378 __ jmp(&medium_size); 379 } 380 381 { 382 // |dst| is a higher address than |src|. Copy backwards. 383 Label unaligned_source, move_first_15, skip_last_move; 384 __ bind(&backward); 385 // |dst| and |src| always point to the end of what's left to copy. 386 __ add(dst, count); 387 __ add(src, count); 388 __ mov(eax, dst); 389 __ sub(eax, src); 390 __ cmp(eax, kMinMoveDistance); 391 __ j(below, &backward_much_overlap); 392 // Copy last 16 bytes. 393 __ movdqu(xmm0, Operand(src, -0x10)); 394 __ movdqu(Operand(dst, -0x10), xmm0); 395 // Find distance to alignment: dst & 0xF 396 __ mov(edx, dst); 397 __ and_(edx, 0xF); 398 __ sub(dst, edx); 399 __ sub(src, edx); 400 __ sub(count, edx); 401 // dst is now aligned. Main copy loop. 402 __ mov(loop_count, count); 403 __ shr(loop_count, 6); 404 // Check if src is also aligned. 405 __ test(src, Immediate(0xF)); 406 __ j(not_zero, &unaligned_source); 407 // Copy loop for aligned source and destination. 408 MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_ALIGNED); 409 // At most 15 bytes to copy. Copy 16 bytes at beginning of string. 410 __ bind(&move_first_15); 411 __ and_(count, 0xF); 412 __ j(zero, &skip_last_move, Label::kNear); 413 __ sub(src, count); 414 __ sub(dst, count); 415 __ movdqu(xmm0, Operand(src, 0)); 416 __ movdqu(Operand(dst, 0), xmm0); 417 __ bind(&skip_last_move); 418 MemMoveEmitPopAndReturn(&masm); 419 420 // Copy loop for unaligned source and aligned destination. 421 __ bind(&unaligned_source); 422 MemMoveEmitMainLoop(&masm, &move_first_15, BACKWARD, MOVE_UNALIGNED); 423 __ jmp(&move_first_15); 424 425 // Less than kMinMoveDistance offset between dst and src. 426 Label loop_until_aligned, first_15_much_overlap; 427 __ bind(&loop_until_aligned); 428 __ dec(src); 429 __ dec(dst); 430 __ mov_b(eax, Operand(src, 0)); 431 __ mov_b(Operand(dst, 0), eax); 432 __ dec(count); 433 __ bind(&backward_much_overlap); // Entry point into this block. 434 __ test(dst, Immediate(0xF)); 435 __ j(not_zero, &loop_until_aligned); 436 // dst is now aligned, src can't be. Main copy loop. 437 __ mov(loop_count, count); 438 __ shr(loop_count, 6); 439 MemMoveEmitMainLoop(&masm, &first_15_much_overlap, 440 BACKWARD, MOVE_UNALIGNED); 441 __ bind(&first_15_much_overlap); 442 __ and_(count, 0xF); 443 __ j(zero, &pop_and_return); 444 // Small/medium handlers expect dst/src to point to the beginning. 445 __ sub(dst, count); 446 __ sub(src, count); 447 __ cmp(count, kSmallCopySize); 448 __ j(below_equal, &small_size); 449 __ jmp(&medium_size); 450 } 451 { 452 // Special handlers for 9 <= copy_size < 64. No assumptions about 453 // alignment or move distance, so all reads must be unaligned and 454 // must happen before any writes. 455 Label f9_16, f17_32, f33_48, f49_63; 456 457 __ bind(&f9_16); 458 __ movdbl(xmm0, Operand(src, 0)); 459 __ movdbl(xmm1, Operand(src, count, times_1, -8)); 460 __ movdbl(Operand(dst, 0), xmm0); 461 __ movdbl(Operand(dst, count, times_1, -8), xmm1); 462 MemMoveEmitPopAndReturn(&masm); 463 464 __ bind(&f17_32); 465 __ movdqu(xmm0, Operand(src, 0)); 466 __ movdqu(xmm1, Operand(src, count, times_1, -0x10)); 467 __ movdqu(Operand(dst, 0x00), xmm0); 468 __ movdqu(Operand(dst, count, times_1, -0x10), xmm1); 469 MemMoveEmitPopAndReturn(&masm); 470 471 __ bind(&f33_48); 472 __ movdqu(xmm0, Operand(src, 0x00)); 473 __ movdqu(xmm1, Operand(src, 0x10)); 474 __ movdqu(xmm2, Operand(src, count, times_1, -0x10)); 475 __ movdqu(Operand(dst, 0x00), xmm0); 476 __ movdqu(Operand(dst, 0x10), xmm1); 477 __ movdqu(Operand(dst, count, times_1, -0x10), xmm2); 478 MemMoveEmitPopAndReturn(&masm); 479 480 __ bind(&f49_63); 481 __ movdqu(xmm0, Operand(src, 0x00)); 482 __ movdqu(xmm1, Operand(src, 0x10)); 483 __ movdqu(xmm2, Operand(src, 0x20)); 484 __ movdqu(xmm3, Operand(src, count, times_1, -0x10)); 485 __ movdqu(Operand(dst, 0x00), xmm0); 486 __ movdqu(Operand(dst, 0x10), xmm1); 487 __ movdqu(Operand(dst, 0x20), xmm2); 488 __ movdqu(Operand(dst, count, times_1, -0x10), xmm3); 489 MemMoveEmitPopAndReturn(&masm); 490 491 medium_handlers = new size_t[4]; 492 medium_handlers[0] = reinterpret_cast<intptr_t>(buffer) + f9_16.pos(); 493 medium_handlers[1] = reinterpret_cast<intptr_t>(buffer) + f17_32.pos(); 494 medium_handlers[2] = reinterpret_cast<intptr_t>(buffer) + f33_48.pos(); 495 medium_handlers[3] = reinterpret_cast<intptr_t>(buffer) + f49_63.pos(); 496 497 __ bind(&medium_size); // Entry point into this block. 498 __ mov(eax, count); 499 __ dec(eax); 500 __ shr(eax, 4); 501 if (FLAG_debug_code) { 502 Label ok; 503 __ cmp(eax, 3); 504 __ j(below_equal, &ok); 505 __ int3(); 506 __ bind(&ok); 507 } 508 __ mov(eax, Operand(eax, times_4, 509 reinterpret_cast<intptr_t>(medium_handlers))); 510 __ jmp(eax); 511 } 512 { 513 // Specialized copiers for copy_size <= 8 bytes. 514 Label f0, f1, f2, f3, f4, f5_8; 515 __ bind(&f0); 516 MemMoveEmitPopAndReturn(&masm); 517 518 __ bind(&f1); 519 __ mov_b(eax, Operand(src, 0)); 520 __ mov_b(Operand(dst, 0), eax); 521 MemMoveEmitPopAndReturn(&masm); 522 523 __ bind(&f2); 524 __ mov_w(eax, Operand(src, 0)); 525 __ mov_w(Operand(dst, 0), eax); 526 MemMoveEmitPopAndReturn(&masm); 527 528 __ bind(&f3); 529 __ mov_w(eax, Operand(src, 0)); 530 __ mov_b(edx, Operand(src, 2)); 531 __ mov_w(Operand(dst, 0), eax); 532 __ mov_b(Operand(dst, 2), edx); 533 MemMoveEmitPopAndReturn(&masm); 534 535 __ bind(&f4); 536 __ mov(eax, Operand(src, 0)); 537 __ mov(Operand(dst, 0), eax); 538 MemMoveEmitPopAndReturn(&masm); 539 540 __ bind(&f5_8); 541 __ mov(eax, Operand(src, 0)); 542 __ mov(edx, Operand(src, count, times_1, -4)); 543 __ mov(Operand(dst, 0), eax); 544 __ mov(Operand(dst, count, times_1, -4), edx); 545 MemMoveEmitPopAndReturn(&masm); 546 547 small_handlers = new size_t[9]; 548 small_handlers[0] = reinterpret_cast<intptr_t>(buffer) + f0.pos(); 549 small_handlers[1] = reinterpret_cast<intptr_t>(buffer) + f1.pos(); 550 small_handlers[2] = reinterpret_cast<intptr_t>(buffer) + f2.pos(); 551 small_handlers[3] = reinterpret_cast<intptr_t>(buffer) + f3.pos(); 552 small_handlers[4] = reinterpret_cast<intptr_t>(buffer) + f4.pos(); 553 small_handlers[5] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos(); 554 small_handlers[6] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos(); 555 small_handlers[7] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos(); 556 small_handlers[8] = reinterpret_cast<intptr_t>(buffer) + f5_8.pos(); 557 558 __ bind(&small_size); // Entry point into this block. 559 if (FLAG_debug_code) { 560 Label ok; 561 __ cmp(count, 8); 562 __ j(below_equal, &ok); 563 __ int3(); 564 __ bind(&ok); 565 } 566 __ mov(eax, Operand(count, times_4, 567 reinterpret_cast<intptr_t>(small_handlers))); 568 __ jmp(eax); 569 } 570 } else { 571 // No SSE2. 572 Label forward; 573 __ cmp(count, 0); 574 __ j(equal, &pop_and_return); 575 __ cmp(dst, src); 576 __ j(above, &backward); 577 __ jmp(&forward); 578 { 579 // Simple forward copier. 580 Label forward_loop_1byte, forward_loop_4byte; 581 __ bind(&forward_loop_4byte); 582 __ mov(eax, Operand(src, 0)); 583 __ sub(count, Immediate(4)); 584 __ add(src, Immediate(4)); 585 __ mov(Operand(dst, 0), eax); 586 __ add(dst, Immediate(4)); 587 __ bind(&forward); // Entry point. 588 __ cmp(count, 3); 589 __ j(above, &forward_loop_4byte); 590 __ bind(&forward_loop_1byte); 591 __ cmp(count, 0); 592 __ j(below_equal, &pop_and_return); 593 __ mov_b(eax, Operand(src, 0)); 594 __ dec(count); 595 __ inc(src); 596 __ mov_b(Operand(dst, 0), eax); 597 __ inc(dst); 598 __ jmp(&forward_loop_1byte); 599 } 600 { 601 // Simple backward copier. 602 Label backward_loop_1byte, backward_loop_4byte, entry_shortcut; 603 __ bind(&backward); 604 __ add(src, count); 605 __ add(dst, count); 606 __ cmp(count, 3); 607 __ j(below_equal, &entry_shortcut); 608 609 __ bind(&backward_loop_4byte); 610 __ sub(src, Immediate(4)); 611 __ sub(count, Immediate(4)); 612 __ mov(eax, Operand(src, 0)); 613 __ sub(dst, Immediate(4)); 614 __ mov(Operand(dst, 0), eax); 615 __ cmp(count, 3); 616 __ j(above, &backward_loop_4byte); 617 __ bind(&backward_loop_1byte); 618 __ cmp(count, 0); 619 __ j(below_equal, &pop_and_return); 620 __ bind(&entry_shortcut); 621 __ dec(src); 622 __ dec(count); 623 __ mov_b(eax, Operand(src, 0)); 624 __ dec(dst); 625 __ mov_b(Operand(dst, 0), eax); 626 __ jmp(&backward_loop_1byte); 627 } 628 } 629 630 __ bind(&pop_and_return); 631 MemMoveEmitPopAndReturn(&masm); 632 633 CodeDesc desc; 634 masm.GetCode(&desc); 635 ASSERT(!RelocInfo::RequiresRelocation(desc)); 636 CPU::FlushICache(buffer, actual_size); 637 OS::ProtectCode(buffer, actual_size); 638 // TODO(jkummerow): It would be nice to register this code creation event 639 // with the PROFILE / GDBJIT system. 640 return FUNCTION_CAST<OS::MemMoveFunction>(buffer); 641 } 642 643 644 #undef __ 645 646 // ------------------------------------------------------------------------- 647 // Code generators 648 649 #define __ ACCESS_MASM(masm) 650 651 652 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition( 653 MacroAssembler* masm, AllocationSiteMode mode, 654 Label* allocation_memento_found) { 655 // ----------- S t a t e ------------- 656 // -- eax : value 657 // -- ebx : target map 658 // -- ecx : key 659 // -- edx : receiver 660 // -- esp[0] : return address 661 // ----------------------------------- 662 if (mode == TRACK_ALLOCATION_SITE) { 663 ASSERT(allocation_memento_found != NULL); 664 __ TestJSArrayForAllocationMemento(edx, edi); 665 __ j(equal, allocation_memento_found); 666 } 667 668 // Set transitioned map. 669 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx); 670 __ RecordWriteField(edx, 671 HeapObject::kMapOffset, 672 ebx, 673 edi, 674 kDontSaveFPRegs, 675 EMIT_REMEMBERED_SET, 676 OMIT_SMI_CHECK); 677 } 678 679 680 void ElementsTransitionGenerator::GenerateSmiToDouble( 681 MacroAssembler* masm, AllocationSiteMode mode, Label* fail) { 682 // ----------- S t a t e ------------- 683 // -- eax : value 684 // -- ebx : target map 685 // -- ecx : key 686 // -- edx : receiver 687 // -- esp[0] : return address 688 // ----------------------------------- 689 Label loop, entry, convert_hole, gc_required, only_change_map; 690 691 if (mode == TRACK_ALLOCATION_SITE) { 692 __ TestJSArrayForAllocationMemento(edx, edi); 693 __ j(equal, fail); 694 } 695 696 // Check for empty arrays, which only require a map transition and no changes 697 // to the backing store. 698 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); 699 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array())); 700 __ j(equal, &only_change_map); 701 702 __ push(eax); 703 __ push(ebx); 704 705 __ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset)); 706 707 // Allocate new FixedDoubleArray. 708 // edx: receiver 709 // edi: length of source FixedArray (smi-tagged) 710 AllocationFlags flags = 711 static_cast<AllocationFlags>(TAG_OBJECT | DOUBLE_ALIGNMENT); 712 __ Allocate(FixedDoubleArray::kHeaderSize, times_8, edi, 713 REGISTER_VALUE_IS_SMI, eax, ebx, no_reg, &gc_required, flags); 714 715 // eax: destination FixedDoubleArray 716 // edi: number of elements 717 // edx: receiver 718 __ mov(FieldOperand(eax, HeapObject::kMapOffset), 719 Immediate(masm->isolate()->factory()->fixed_double_array_map())); 720 __ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi); 721 __ mov(esi, FieldOperand(edx, JSObject::kElementsOffset)); 722 // Replace receiver's backing store with newly created FixedDoubleArray. 723 __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax); 724 __ mov(ebx, eax); 725 __ RecordWriteField(edx, 726 JSObject::kElementsOffset, 727 ebx, 728 edi, 729 kDontSaveFPRegs, 730 EMIT_REMEMBERED_SET, 731 OMIT_SMI_CHECK); 732 733 __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset)); 734 735 // Prepare for conversion loop. 736 ExternalReference canonical_the_hole_nan_reference = 737 ExternalReference::address_of_the_hole_nan(); 738 XMMRegister the_hole_nan = xmm1; 739 if (CpuFeatures::IsSupported(SSE2)) { 740 CpuFeatureScope use_sse2(masm, SSE2); 741 __ movdbl(the_hole_nan, 742 Operand::StaticVariable(canonical_the_hole_nan_reference)); 743 } 744 __ jmp(&entry); 745 746 // Call into runtime if GC is required. 747 __ bind(&gc_required); 748 // Restore registers before jumping into runtime. 749 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 750 __ pop(ebx); 751 __ pop(eax); 752 __ jmp(fail); 753 754 // Convert and copy elements 755 // esi: source FixedArray 756 __ bind(&loop); 757 __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize)); 758 // ebx: current element from source 759 // edi: index of current element 760 __ JumpIfNotSmi(ebx, &convert_hole); 761 762 // Normal smi, convert it to double and store. 763 __ SmiUntag(ebx); 764 if (CpuFeatures::IsSupported(SSE2)) { 765 CpuFeatureScope fscope(masm, SSE2); 766 __ cvtsi2sd(xmm0, ebx); 767 __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize), 768 xmm0); 769 } else { 770 __ push(ebx); 771 __ fild_s(Operand(esp, 0)); 772 __ pop(ebx); 773 __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize)); 774 } 775 __ jmp(&entry); 776 777 // Found hole, store hole_nan_as_double instead. 778 __ bind(&convert_hole); 779 780 if (FLAG_debug_code) { 781 __ cmp(ebx, masm->isolate()->factory()->the_hole_value()); 782 __ Assert(equal, kObjectFoundInSmiOnlyArray); 783 } 784 785 if (CpuFeatures::IsSupported(SSE2)) { 786 CpuFeatureScope use_sse2(masm, SSE2); 787 __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize), 788 the_hole_nan); 789 } else { 790 __ fld_d(Operand::StaticVariable(canonical_the_hole_nan_reference)); 791 __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize)); 792 } 793 794 __ bind(&entry); 795 __ sub(edi, Immediate(Smi::FromInt(1))); 796 __ j(not_sign, &loop); 797 798 __ pop(ebx); 799 __ pop(eax); 800 801 // Restore esi. 802 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 803 804 __ bind(&only_change_map); 805 // eax: value 806 // ebx: target map 807 // Set transitioned map. 808 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx); 809 __ RecordWriteField(edx, 810 HeapObject::kMapOffset, 811 ebx, 812 edi, 813 kDontSaveFPRegs, 814 OMIT_REMEMBERED_SET, 815 OMIT_SMI_CHECK); 816 } 817 818 819 void ElementsTransitionGenerator::GenerateDoubleToObject( 820 MacroAssembler* masm, AllocationSiteMode mode, Label* fail) { 821 // ----------- S t a t e ------------- 822 // -- eax : value 823 // -- ebx : target map 824 // -- ecx : key 825 // -- edx : receiver 826 // -- esp[0] : return address 827 // ----------------------------------- 828 Label loop, entry, convert_hole, gc_required, only_change_map, success; 829 830 if (mode == TRACK_ALLOCATION_SITE) { 831 __ TestJSArrayForAllocationMemento(edx, edi); 832 __ j(equal, fail); 833 } 834 835 // Check for empty arrays, which only require a map transition and no changes 836 // to the backing store. 837 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); 838 __ cmp(edi, Immediate(masm->isolate()->factory()->empty_fixed_array())); 839 __ j(equal, &only_change_map); 840 841 __ push(eax); 842 __ push(edx); 843 __ push(ebx); 844 845 __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset)); 846 847 // Allocate new FixedArray. 848 // ebx: length of source FixedDoubleArray (smi-tagged) 849 __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize)); 850 __ Allocate(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT); 851 852 // eax: destination FixedArray 853 // ebx: number of elements 854 __ mov(FieldOperand(eax, HeapObject::kMapOffset), 855 Immediate(masm->isolate()->factory()->fixed_array_map())); 856 __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx); 857 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); 858 859 __ jmp(&entry); 860 861 // ebx: target map 862 // edx: receiver 863 // Set transitioned map. 864 __ bind(&only_change_map); 865 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx); 866 __ RecordWriteField(edx, 867 HeapObject::kMapOffset, 868 ebx, 869 edi, 870 kDontSaveFPRegs, 871 OMIT_REMEMBERED_SET, 872 OMIT_SMI_CHECK); 873 __ jmp(&success); 874 875 // Call into runtime if GC is required. 876 __ bind(&gc_required); 877 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 878 __ pop(ebx); 879 __ pop(edx); 880 __ pop(eax); 881 __ jmp(fail); 882 883 // Box doubles into heap numbers. 884 // edi: source FixedDoubleArray 885 // eax: destination FixedArray 886 __ bind(&loop); 887 // ebx: index of current element (smi-tagged) 888 uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32); 889 __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32)); 890 __ j(equal, &convert_hole); 891 892 // Non-hole double, copy value into a heap number. 893 __ AllocateHeapNumber(edx, esi, no_reg, &gc_required); 894 // edx: new heap number 895 if (CpuFeatures::IsSupported(SSE2)) { 896 CpuFeatureScope fscope(masm, SSE2); 897 __ movdbl(xmm0, 898 FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize)); 899 __ movdbl(FieldOperand(edx, HeapNumber::kValueOffset), xmm0); 900 } else { 901 __ mov(esi, FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize)); 902 __ mov(FieldOperand(edx, HeapNumber::kValueOffset), esi); 903 __ mov(esi, FieldOperand(edi, ebx, times_4, offset)); 904 __ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi); 905 } 906 __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx); 907 __ mov(esi, ebx); 908 __ RecordWriteArray(eax, 909 edx, 910 esi, 911 kDontSaveFPRegs, 912 EMIT_REMEMBERED_SET, 913 OMIT_SMI_CHECK); 914 __ jmp(&entry, Label::kNear); 915 916 // Replace the-hole NaN with the-hole pointer. 917 __ bind(&convert_hole); 918 __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), 919 masm->isolate()->factory()->the_hole_value()); 920 921 __ bind(&entry); 922 __ sub(ebx, Immediate(Smi::FromInt(1))); 923 __ j(not_sign, &loop); 924 925 __ pop(ebx); 926 __ pop(edx); 927 // ebx: target map 928 // edx: receiver 929 // Set transitioned map. 930 __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx); 931 __ RecordWriteField(edx, 932 HeapObject::kMapOffset, 933 ebx, 934 edi, 935 kDontSaveFPRegs, 936 OMIT_REMEMBERED_SET, 937 OMIT_SMI_CHECK); 938 // Replace receiver's backing store with newly created and filled FixedArray. 939 __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax); 940 __ RecordWriteField(edx, 941 JSObject::kElementsOffset, 942 eax, 943 edi, 944 kDontSaveFPRegs, 945 EMIT_REMEMBERED_SET, 946 OMIT_SMI_CHECK); 947 948 // Restore registers. 949 __ pop(eax); 950 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 951 952 __ bind(&success); 953 } 954 955 956 void StringCharLoadGenerator::Generate(MacroAssembler* masm, 957 Factory* factory, 958 Register string, 959 Register index, 960 Register result, 961 Label* call_runtime) { 962 // Fetch the instance type of the receiver into result register. 963 __ mov(result, FieldOperand(string, HeapObject::kMapOffset)); 964 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); 965 966 // We need special handling for indirect strings. 967 Label check_sequential; 968 __ test(result, Immediate(kIsIndirectStringMask)); 969 __ j(zero, &check_sequential, Label::kNear); 970 971 // Dispatch on the indirect string shape: slice or cons. 972 Label cons_string; 973 __ test(result, Immediate(kSlicedNotConsMask)); 974 __ j(zero, &cons_string, Label::kNear); 975 976 // Handle slices. 977 Label indirect_string_loaded; 978 __ mov(result, FieldOperand(string, SlicedString::kOffsetOffset)); 979 __ SmiUntag(result); 980 __ add(index, result); 981 __ mov(string, FieldOperand(string, SlicedString::kParentOffset)); 982 __ jmp(&indirect_string_loaded, Label::kNear); 983 984 // Handle cons strings. 985 // Check whether the right hand side is the empty string (i.e. if 986 // this is really a flat string in a cons string). If that is not 987 // the case we would rather go to the runtime system now to flatten 988 // the string. 989 __ bind(&cons_string); 990 __ cmp(FieldOperand(string, ConsString::kSecondOffset), 991 Immediate(factory->empty_string())); 992 __ j(not_equal, call_runtime); 993 __ mov(string, FieldOperand(string, ConsString::kFirstOffset)); 994 995 __ bind(&indirect_string_loaded); 996 __ mov(result, FieldOperand(string, HeapObject::kMapOffset)); 997 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); 998 999 // Distinguish sequential and external strings. Only these two string 1000 // representations can reach here (slices and flat cons strings have been 1001 // reduced to the underlying sequential or external string). 1002 Label seq_string; 1003 __ bind(&check_sequential); 1004 STATIC_ASSERT(kSeqStringTag == 0); 1005 __ test(result, Immediate(kStringRepresentationMask)); 1006 __ j(zero, &seq_string, Label::kNear); 1007 1008 // Handle external strings. 1009 Label ascii_external, done; 1010 if (FLAG_debug_code) { 1011 // Assert that we do not have a cons or slice (indirect strings) here. 1012 // Sequential strings have already been ruled out. 1013 __ test(result, Immediate(kIsIndirectStringMask)); 1014 __ Assert(zero, kExternalStringExpectedButNotFound); 1015 } 1016 // Rule out short external strings. 1017 STATIC_CHECK(kShortExternalStringTag != 0); 1018 __ test_b(result, kShortExternalStringMask); 1019 __ j(not_zero, call_runtime); 1020 // Check encoding. 1021 STATIC_ASSERT(kTwoByteStringTag == 0); 1022 __ test_b(result, kStringEncodingMask); 1023 __ mov(result, FieldOperand(string, ExternalString::kResourceDataOffset)); 1024 __ j(not_equal, &ascii_external, Label::kNear); 1025 // Two-byte string. 1026 __ movzx_w(result, Operand(result, index, times_2, 0)); 1027 __ jmp(&done, Label::kNear); 1028 __ bind(&ascii_external); 1029 // Ascii string. 1030 __ movzx_b(result, Operand(result, index, times_1, 0)); 1031 __ jmp(&done, Label::kNear); 1032 1033 // Dispatch on the encoding: ASCII or two-byte. 1034 Label ascii; 1035 __ bind(&seq_string); 1036 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); 1037 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 1038 __ test(result, Immediate(kStringEncodingMask)); 1039 __ j(not_zero, &ascii, Label::kNear); 1040 1041 // Two-byte string. 1042 // Load the two-byte character code into the result register. 1043 __ movzx_w(result, FieldOperand(string, 1044 index, 1045 times_2, 1046 SeqTwoByteString::kHeaderSize)); 1047 __ jmp(&done, Label::kNear); 1048 1049 // Ascii string. 1050 // Load the byte into the result register. 1051 __ bind(&ascii); 1052 __ movzx_b(result, FieldOperand(string, 1053 index, 1054 times_1, 1055 SeqOneByteString::kHeaderSize)); 1056 __ bind(&done); 1057 } 1058 1059 1060 static Operand ExpConstant(int index) { 1061 return Operand::StaticVariable(ExternalReference::math_exp_constants(index)); 1062 } 1063 1064 1065 void MathExpGenerator::EmitMathExp(MacroAssembler* masm, 1066 XMMRegister input, 1067 XMMRegister result, 1068 XMMRegister double_scratch, 1069 Register temp1, 1070 Register temp2) { 1071 ASSERT(!input.is(double_scratch)); 1072 ASSERT(!input.is(result)); 1073 ASSERT(!result.is(double_scratch)); 1074 ASSERT(!temp1.is(temp2)); 1075 ASSERT(ExternalReference::math_exp_constants(0).address() != NULL); 1076 1077 Label done; 1078 1079 __ movdbl(double_scratch, ExpConstant(0)); 1080 __ xorpd(result, result); 1081 __ ucomisd(double_scratch, input); 1082 __ j(above_equal, &done); 1083 __ ucomisd(input, ExpConstant(1)); 1084 __ movdbl(result, ExpConstant(2)); 1085 __ j(above_equal, &done); 1086 __ movdbl(double_scratch, ExpConstant(3)); 1087 __ movdbl(result, ExpConstant(4)); 1088 __ mulsd(double_scratch, input); 1089 __ addsd(double_scratch, result); 1090 __ movd(temp2, double_scratch); 1091 __ subsd(double_scratch, result); 1092 __ movdbl(result, ExpConstant(6)); 1093 __ mulsd(double_scratch, ExpConstant(5)); 1094 __ subsd(double_scratch, input); 1095 __ subsd(result, double_scratch); 1096 __ movsd(input, double_scratch); 1097 __ mulsd(input, double_scratch); 1098 __ mulsd(result, input); 1099 __ mov(temp1, temp2); 1100 __ mulsd(result, ExpConstant(7)); 1101 __ subsd(result, double_scratch); 1102 __ add(temp1, Immediate(0x1ff800)); 1103 __ addsd(result, ExpConstant(8)); 1104 __ and_(temp2, Immediate(0x7ff)); 1105 __ shr(temp1, 11); 1106 __ shl(temp1, 20); 1107 __ movd(input, temp1); 1108 __ pshufd(input, input, static_cast<uint8_t>(0xe1)); // Order: 11 10 00 01 1109 __ movdbl(double_scratch, Operand::StaticArray( 1110 temp2, times_8, ExternalReference::math_exp_log_table())); 1111 __ por(input, double_scratch); 1112 __ mulsd(result, input); 1113 __ bind(&done); 1114 } 1115 1116 #undef __ 1117 1118 static const int kNoCodeAgeSequenceLength = 5; 1119 1120 static byte* GetNoCodeAgeSequence(uint32_t* length) { 1121 static bool initialized = false; 1122 static byte sequence[kNoCodeAgeSequenceLength]; 1123 *length = kNoCodeAgeSequenceLength; 1124 if (!initialized) { 1125 // The sequence of instructions that is patched out for aging code is the 1126 // following boilerplate stack-building prologue that is found both in 1127 // FUNCTION and OPTIMIZED_FUNCTION code: 1128 CodePatcher patcher(sequence, kNoCodeAgeSequenceLength); 1129 patcher.masm()->push(ebp); 1130 patcher.masm()->mov(ebp, esp); 1131 patcher.masm()->push(esi); 1132 patcher.masm()->push(edi); 1133 initialized = true; 1134 } 1135 return sequence; 1136 } 1137 1138 1139 bool Code::IsYoungSequence(byte* sequence) { 1140 uint32_t young_length; 1141 byte* young_sequence = GetNoCodeAgeSequence(&young_length); 1142 bool result = (!memcmp(sequence, young_sequence, young_length)); 1143 ASSERT(result || *sequence == kCallOpcode); 1144 return result; 1145 } 1146 1147 1148 void Code::GetCodeAgeAndParity(byte* sequence, Age* age, 1149 MarkingParity* parity) { 1150 if (IsYoungSequence(sequence)) { 1151 *age = kNoAge; 1152 *parity = NO_MARKING_PARITY; 1153 } else { 1154 sequence++; // Skip the kCallOpcode byte 1155 Address target_address = sequence + *reinterpret_cast<int*>(sequence) + 1156 Assembler::kCallTargetAddressOffset; 1157 Code* stub = GetCodeFromTargetAddress(target_address); 1158 GetCodeAgeAndParity(stub, age, parity); 1159 } 1160 } 1161 1162 1163 void Code::PatchPlatformCodeAge(byte* sequence, 1164 Code::Age age, 1165 MarkingParity parity) { 1166 uint32_t young_length; 1167 byte* young_sequence = GetNoCodeAgeSequence(&young_length); 1168 if (age == kNoAge) { 1169 CopyBytes(sequence, young_sequence, young_length); 1170 CPU::FlushICache(sequence, young_length); 1171 } else { 1172 Code* stub = GetCodeAgeStub(age, parity); 1173 CodePatcher patcher(sequence, young_length); 1174 patcher.masm()->call(stub->instruction_start(), RelocInfo::NONE32); 1175 } 1176 } 1177 1178 1179 } } // namespace v8::internal 1180 1181 #endif // V8_TARGET_ARCH_IA32 1182