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 defined(V8_TARGET_ARCH_IA32) 31 32 #include "bootstrapper.h" 33 #include "code-stubs.h" 34 #include "isolate.h" 35 #include "jsregexp.h" 36 #include "regexp-macro-assembler.h" 37 #include "stub-cache.h" 38 #include "codegen.h" 39 40 namespace v8 { 41 namespace internal { 42 43 #define __ ACCESS_MASM(masm) 44 45 void ToNumberStub::Generate(MacroAssembler* masm) { 46 // The ToNumber stub takes one argument in eax. 47 Label check_heap_number, call_builtin; 48 __ JumpIfNotSmi(eax, &check_heap_number, Label::kNear); 49 __ ret(0); 50 51 __ bind(&check_heap_number); 52 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 53 Factory* factory = masm->isolate()->factory(); 54 __ cmp(ebx, Immediate(factory->heap_number_map())); 55 __ j(not_equal, &call_builtin, Label::kNear); 56 __ ret(0); 57 58 __ bind(&call_builtin); 59 __ pop(ecx); // Pop return address. 60 __ push(eax); 61 __ push(ecx); // Push return address. 62 __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_FUNCTION); 63 } 64 65 66 void FastNewClosureStub::Generate(MacroAssembler* masm) { 67 // Create a new closure from the given function info in new 68 // space. Set the context to the current context in esi. 69 Label gc; 70 __ AllocateInNewSpace(JSFunction::kSize, eax, ebx, ecx, &gc, TAG_OBJECT); 71 72 // Get the function info from the stack. 73 __ mov(edx, Operand(esp, 1 * kPointerSize)); 74 75 int map_index = (language_mode_ == CLASSIC_MODE) 76 ? Context::FUNCTION_MAP_INDEX 77 : Context::STRICT_MODE_FUNCTION_MAP_INDEX; 78 79 // Compute the function map in the current global context and set that 80 // as the map of the allocated object. 81 __ mov(ecx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 82 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset)); 83 __ mov(ecx, Operand(ecx, Context::SlotOffset(map_index))); 84 __ mov(FieldOperand(eax, JSObject::kMapOffset), ecx); 85 86 // Initialize the rest of the function. We don't have to update the 87 // write barrier because the allocated object is in new space. 88 Factory* factory = masm->isolate()->factory(); 89 __ mov(ebx, Immediate(factory->empty_fixed_array())); 90 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ebx); 91 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx); 92 __ mov(FieldOperand(eax, JSFunction::kPrototypeOrInitialMapOffset), 93 Immediate(factory->the_hole_value())); 94 __ mov(FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset), edx); 95 __ mov(FieldOperand(eax, JSFunction::kContextOffset), esi); 96 __ mov(FieldOperand(eax, JSFunction::kLiteralsOffset), ebx); 97 __ mov(FieldOperand(eax, JSFunction::kNextFunctionLinkOffset), 98 Immediate(factory->undefined_value())); 99 100 // Initialize the code pointer in the function to be the one 101 // found in the shared function info object. 102 __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kCodeOffset)); 103 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); 104 __ mov(FieldOperand(eax, JSFunction::kCodeEntryOffset), edx); 105 106 // Return and remove the on-stack parameter. 107 __ ret(1 * kPointerSize); 108 109 // Create a new closure through the slower runtime call. 110 __ bind(&gc); 111 __ pop(ecx); // Temporarily remove return address. 112 __ pop(edx); 113 __ push(esi); 114 __ push(edx); 115 __ push(Immediate(factory->false_value())); 116 __ push(ecx); // Restore return address. 117 __ TailCallRuntime(Runtime::kNewClosure, 3, 1); 118 } 119 120 121 void FastNewContextStub::Generate(MacroAssembler* masm) { 122 // Try to allocate the context in new space. 123 Label gc; 124 int length = slots_ + Context::MIN_CONTEXT_SLOTS; 125 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, 126 eax, ebx, ecx, &gc, TAG_OBJECT); 127 128 // Get the function from the stack. 129 __ mov(ecx, Operand(esp, 1 * kPointerSize)); 130 131 // Set up the object header. 132 Factory* factory = masm->isolate()->factory(); 133 __ mov(FieldOperand(eax, HeapObject::kMapOffset), 134 factory->function_context_map()); 135 __ mov(FieldOperand(eax, Context::kLengthOffset), 136 Immediate(Smi::FromInt(length))); 137 138 // Set up the fixed slots. 139 __ Set(ebx, Immediate(0)); // Set to NULL. 140 __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx); 141 __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), esi); 142 __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx); 143 144 // Copy the global object from the previous context. 145 __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 146 __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); 147 148 // Initialize the rest of the slots to undefined. 149 __ mov(ebx, factory->undefined_value()); 150 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { 151 __ mov(Operand(eax, Context::SlotOffset(i)), ebx); 152 } 153 154 // Return and remove the on-stack parameter. 155 __ mov(esi, eax); 156 __ ret(1 * kPointerSize); 157 158 // Need to collect. Call into runtime system. 159 __ bind(&gc); 160 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); 161 } 162 163 164 void FastNewBlockContextStub::Generate(MacroAssembler* masm) { 165 // Stack layout on entry: 166 // 167 // [esp + (1 * kPointerSize)]: function 168 // [esp + (2 * kPointerSize)]: serialized scope info 169 170 // Try to allocate the context in new space. 171 Label gc; 172 int length = slots_ + Context::MIN_CONTEXT_SLOTS; 173 __ AllocateInNewSpace(FixedArray::SizeFor(length), 174 eax, ebx, ecx, &gc, TAG_OBJECT); 175 176 // Get the function or sentinel from the stack. 177 __ mov(ecx, Operand(esp, 1 * kPointerSize)); 178 179 // Get the serialized scope info from the stack. 180 __ mov(ebx, Operand(esp, 2 * kPointerSize)); 181 182 // Set up the object header. 183 Factory* factory = masm->isolate()->factory(); 184 __ mov(FieldOperand(eax, HeapObject::kMapOffset), 185 factory->block_context_map()); 186 __ mov(FieldOperand(eax, Context::kLengthOffset), 187 Immediate(Smi::FromInt(length))); 188 189 // If this block context is nested in the global context we get a smi 190 // sentinel instead of a function. The block context should get the 191 // canonical empty function of the global context as its closure which 192 // we still have to look up. 193 Label after_sentinel; 194 __ JumpIfNotSmi(ecx, &after_sentinel, Label::kNear); 195 if (FLAG_debug_code) { 196 const char* message = "Expected 0 as a Smi sentinel"; 197 __ cmp(ecx, 0); 198 __ Assert(equal, message); 199 } 200 __ mov(ecx, GlobalObjectOperand()); 201 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalContextOffset)); 202 __ mov(ecx, ContextOperand(ecx, Context::CLOSURE_INDEX)); 203 __ bind(&after_sentinel); 204 205 // Set up the fixed slots. 206 __ mov(ContextOperand(eax, Context::CLOSURE_INDEX), ecx); 207 __ mov(ContextOperand(eax, Context::PREVIOUS_INDEX), esi); 208 __ mov(ContextOperand(eax, Context::EXTENSION_INDEX), ebx); 209 210 // Copy the global object from the previous context. 211 __ mov(ebx, ContextOperand(esi, Context::GLOBAL_INDEX)); 212 __ mov(ContextOperand(eax, Context::GLOBAL_INDEX), ebx); 213 214 // Initialize the rest of the slots to the hole value. 215 if (slots_ == 1) { 216 __ mov(ContextOperand(eax, Context::MIN_CONTEXT_SLOTS), 217 factory->the_hole_value()); 218 } else { 219 __ mov(ebx, factory->the_hole_value()); 220 for (int i = 0; i < slots_; i++) { 221 __ mov(ContextOperand(eax, i + Context::MIN_CONTEXT_SLOTS), ebx); 222 } 223 } 224 225 // Return and remove the on-stack parameters. 226 __ mov(esi, eax); 227 __ ret(2 * kPointerSize); 228 229 // Need to collect. Call into runtime system. 230 __ bind(&gc); 231 __ TailCallRuntime(Runtime::kPushBlockContext, 2, 1); 232 } 233 234 235 static void GenerateFastCloneShallowArrayCommon( 236 MacroAssembler* masm, 237 int length, 238 FastCloneShallowArrayStub::Mode mode, 239 Label* fail) { 240 // Registers on entry: 241 // 242 // ecx: boilerplate literal array. 243 ASSERT(mode != FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS); 244 245 // All sizes here are multiples of kPointerSize. 246 int elements_size = 0; 247 if (length > 0) { 248 elements_size = mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS 249 ? FixedDoubleArray::SizeFor(length) 250 : FixedArray::SizeFor(length); 251 } 252 int size = JSArray::kSize + elements_size; 253 254 // Allocate both the JS array and the elements array in one big 255 // allocation. This avoids multiple limit checks. 256 __ AllocateInNewSpace(size, eax, ebx, edx, fail, TAG_OBJECT); 257 258 // Copy the JS array part. 259 for (int i = 0; i < JSArray::kSize; i += kPointerSize) { 260 if ((i != JSArray::kElementsOffset) || (length == 0)) { 261 __ mov(ebx, FieldOperand(ecx, i)); 262 __ mov(FieldOperand(eax, i), ebx); 263 } 264 } 265 266 if (length > 0) { 267 // Get hold of the elements array of the boilerplate and setup the 268 // elements pointer in the resulting object. 269 __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); 270 __ lea(edx, Operand(eax, JSArray::kSize)); 271 __ mov(FieldOperand(eax, JSArray::kElementsOffset), edx); 272 273 // Copy the elements array. 274 if (mode == FastCloneShallowArrayStub::CLONE_ELEMENTS) { 275 for (int i = 0; i < elements_size; i += kPointerSize) { 276 __ mov(ebx, FieldOperand(ecx, i)); 277 __ mov(FieldOperand(edx, i), ebx); 278 } 279 } else { 280 ASSERT(mode == FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS); 281 int i; 282 for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) { 283 __ mov(ebx, FieldOperand(ecx, i)); 284 __ mov(FieldOperand(edx, i), ebx); 285 } 286 while (i < elements_size) { 287 __ fld_d(FieldOperand(ecx, i)); 288 __ fstp_d(FieldOperand(edx, i)); 289 i += kDoubleSize; 290 } 291 ASSERT(i == elements_size); 292 } 293 } 294 } 295 296 297 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { 298 // Stack layout on entry: 299 // 300 // [esp + kPointerSize]: constant elements. 301 // [esp + (2 * kPointerSize)]: literal index. 302 // [esp + (3 * kPointerSize)]: literals array. 303 304 // Load boilerplate object into ecx and check if we need to create a 305 // boilerplate. 306 __ mov(ecx, Operand(esp, 3 * kPointerSize)); 307 __ mov(eax, Operand(esp, 2 * kPointerSize)); 308 STATIC_ASSERT(kPointerSize == 4); 309 STATIC_ASSERT(kSmiTagSize == 1); 310 STATIC_ASSERT(kSmiTag == 0); 311 __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size, 312 FixedArray::kHeaderSize)); 313 Factory* factory = masm->isolate()->factory(); 314 __ cmp(ecx, factory->undefined_value()); 315 Label slow_case; 316 __ j(equal, &slow_case); 317 318 FastCloneShallowArrayStub::Mode mode = mode_; 319 // ecx is boilerplate object. 320 if (mode == CLONE_ANY_ELEMENTS) { 321 Label double_elements, check_fast_elements; 322 __ mov(ebx, FieldOperand(ecx, JSArray::kElementsOffset)); 323 __ CheckMap(ebx, factory->fixed_cow_array_map(), 324 &check_fast_elements, DONT_DO_SMI_CHECK); 325 GenerateFastCloneShallowArrayCommon(masm, 0, 326 COPY_ON_WRITE_ELEMENTS, &slow_case); 327 __ ret(3 * kPointerSize); 328 329 __ bind(&check_fast_elements); 330 __ CheckMap(ebx, factory->fixed_array_map(), 331 &double_elements, DONT_DO_SMI_CHECK); 332 GenerateFastCloneShallowArrayCommon(masm, length_, 333 CLONE_ELEMENTS, &slow_case); 334 __ ret(3 * kPointerSize); 335 336 __ bind(&double_elements); 337 mode = CLONE_DOUBLE_ELEMENTS; 338 // Fall through to generate the code to handle double elements. 339 } 340 341 if (FLAG_debug_code) { 342 const char* message; 343 Handle<Map> expected_map; 344 if (mode == CLONE_ELEMENTS) { 345 message = "Expected (writable) fixed array"; 346 expected_map = factory->fixed_array_map(); 347 } else if (mode == CLONE_DOUBLE_ELEMENTS) { 348 message = "Expected (writable) fixed double array"; 349 expected_map = factory->fixed_double_array_map(); 350 } else { 351 ASSERT(mode == COPY_ON_WRITE_ELEMENTS); 352 message = "Expected copy-on-write fixed array"; 353 expected_map = factory->fixed_cow_array_map(); 354 } 355 __ push(ecx); 356 __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); 357 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map); 358 __ Assert(equal, message); 359 __ pop(ecx); 360 } 361 362 GenerateFastCloneShallowArrayCommon(masm, length_, mode, &slow_case); 363 // Return and remove the on-stack parameters. 364 __ ret(3 * kPointerSize); 365 366 __ bind(&slow_case); 367 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); 368 } 369 370 371 void FastCloneShallowObjectStub::Generate(MacroAssembler* masm) { 372 // Stack layout on entry: 373 // 374 // [esp + kPointerSize]: object literal flags. 375 // [esp + (2 * kPointerSize)]: constant properties. 376 // [esp + (3 * kPointerSize)]: literal index. 377 // [esp + (4 * kPointerSize)]: literals array. 378 379 // Load boilerplate object into ecx and check if we need to create a 380 // boilerplate. 381 Label slow_case; 382 __ mov(ecx, Operand(esp, 4 * kPointerSize)); 383 __ mov(eax, Operand(esp, 3 * kPointerSize)); 384 STATIC_ASSERT(kPointerSize == 4); 385 STATIC_ASSERT(kSmiTagSize == 1); 386 STATIC_ASSERT(kSmiTag == 0); 387 __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size, 388 FixedArray::kHeaderSize)); 389 Factory* factory = masm->isolate()->factory(); 390 __ cmp(ecx, factory->undefined_value()); 391 __ j(equal, &slow_case); 392 393 // Check that the boilerplate contains only fast properties and we can 394 // statically determine the instance size. 395 int size = JSObject::kHeaderSize + length_ * kPointerSize; 396 __ mov(eax, FieldOperand(ecx, HeapObject::kMapOffset)); 397 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceSizeOffset)); 398 __ cmp(eax, Immediate(size >> kPointerSizeLog2)); 399 __ j(not_equal, &slow_case); 400 401 // Allocate the JS object and copy header together with all in-object 402 // properties from the boilerplate. 403 __ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT); 404 for (int i = 0; i < size; i += kPointerSize) { 405 __ mov(ebx, FieldOperand(ecx, i)); 406 __ mov(FieldOperand(eax, i), ebx); 407 } 408 409 // Return and remove the on-stack parameters. 410 __ ret(4 * kPointerSize); 411 412 __ bind(&slow_case); 413 __ TailCallRuntime(Runtime::kCreateObjectLiteralShallow, 4, 1); 414 } 415 416 417 // The stub expects its argument on the stack and returns its result in tos_: 418 // zero for false, and a non-zero value for true. 419 void ToBooleanStub::Generate(MacroAssembler* masm) { 420 // This stub overrides SometimesSetsUpAFrame() to return false. That means 421 // we cannot call anything that could cause a GC from this stub. 422 Label patch; 423 Factory* factory = masm->isolate()->factory(); 424 const Register argument = eax; 425 const Register map = edx; 426 427 if (!types_.IsEmpty()) { 428 __ mov(argument, Operand(esp, 1 * kPointerSize)); 429 } 430 431 // undefined -> false 432 CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false); 433 434 // Boolean -> its value 435 CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false); 436 CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true); 437 438 // 'null' -> false. 439 CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false); 440 441 if (types_.Contains(SMI)) { 442 // Smis: 0 -> false, all other -> true 443 Label not_smi; 444 __ JumpIfNotSmi(argument, ¬_smi, Label::kNear); 445 // argument contains the correct return value already. 446 if (!tos_.is(argument)) { 447 __ mov(tos_, argument); 448 } 449 __ ret(1 * kPointerSize); 450 __ bind(¬_smi); 451 } else if (types_.NeedsMap()) { 452 // If we need a map later and have a Smi -> patch. 453 __ JumpIfSmi(argument, &patch, Label::kNear); 454 } 455 456 if (types_.NeedsMap()) { 457 __ mov(map, FieldOperand(argument, HeapObject::kMapOffset)); 458 459 if (types_.CanBeUndetectable()) { 460 __ test_b(FieldOperand(map, Map::kBitFieldOffset), 461 1 << Map::kIsUndetectable); 462 // Undetectable -> false. 463 Label not_undetectable; 464 __ j(zero, ¬_undetectable, Label::kNear); 465 __ Set(tos_, Immediate(0)); 466 __ ret(1 * kPointerSize); 467 __ bind(¬_undetectable); 468 } 469 } 470 471 if (types_.Contains(SPEC_OBJECT)) { 472 // spec object -> true. 473 Label not_js_object; 474 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); 475 __ j(below, ¬_js_object, Label::kNear); 476 // argument contains the correct return value already. 477 if (!tos_.is(argument)) { 478 __ Set(tos_, Immediate(1)); 479 } 480 __ ret(1 * kPointerSize); 481 __ bind(¬_js_object); 482 } 483 484 if (types_.Contains(STRING)) { 485 // String value -> false iff empty. 486 Label not_string; 487 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); 488 __ j(above_equal, ¬_string, Label::kNear); 489 __ mov(tos_, FieldOperand(argument, String::kLengthOffset)); 490 __ ret(1 * kPointerSize); // the string length is OK as the return value 491 __ bind(¬_string); 492 } 493 494 if (types_.Contains(HEAP_NUMBER)) { 495 // heap number -> false iff +0, -0, or NaN. 496 Label not_heap_number, false_result; 497 __ cmp(map, factory->heap_number_map()); 498 __ j(not_equal, ¬_heap_number, Label::kNear); 499 __ fldz(); 500 __ fld_d(FieldOperand(argument, HeapNumber::kValueOffset)); 501 __ FCmp(); 502 __ j(zero, &false_result, Label::kNear); 503 // argument contains the correct return value already. 504 if (!tos_.is(argument)) { 505 __ Set(tos_, Immediate(1)); 506 } 507 __ ret(1 * kPointerSize); 508 __ bind(&false_result); 509 __ Set(tos_, Immediate(0)); 510 __ ret(1 * kPointerSize); 511 __ bind(¬_heap_number); 512 } 513 514 __ bind(&patch); 515 GenerateTypeTransition(masm); 516 } 517 518 519 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { 520 // We don't allow a GC during a store buffer overflow so there is no need to 521 // store the registers in any particular way, but we do have to store and 522 // restore them. 523 __ pushad(); 524 if (save_doubles_ == kSaveFPRegs) { 525 CpuFeatures::Scope scope(SSE2); 526 __ sub(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); 527 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { 528 XMMRegister reg = XMMRegister::from_code(i); 529 __ movdbl(Operand(esp, i * kDoubleSize), reg); 530 } 531 } 532 const int argument_count = 1; 533 534 AllowExternalCallThatCantCauseGC scope(masm); 535 __ PrepareCallCFunction(argument_count, ecx); 536 __ mov(Operand(esp, 0 * kPointerSize), 537 Immediate(ExternalReference::isolate_address())); 538 __ CallCFunction( 539 ExternalReference::store_buffer_overflow_function(masm->isolate()), 540 argument_count); 541 if (save_doubles_ == kSaveFPRegs) { 542 CpuFeatures::Scope scope(SSE2); 543 for (int i = 0; i < XMMRegister::kNumRegisters; i++) { 544 XMMRegister reg = XMMRegister::from_code(i); 545 __ movdbl(reg, Operand(esp, i * kDoubleSize)); 546 } 547 __ add(esp, Immediate(kDoubleSize * XMMRegister::kNumRegisters)); 548 } 549 __ popad(); 550 __ ret(0); 551 } 552 553 554 void ToBooleanStub::CheckOddball(MacroAssembler* masm, 555 Type type, 556 Heap::RootListIndex value, 557 bool result) { 558 const Register argument = eax; 559 if (types_.Contains(type)) { 560 // If we see an expected oddball, return its ToBoolean value tos_. 561 Label different_value; 562 __ CompareRoot(argument, value); 563 __ j(not_equal, &different_value, Label::kNear); 564 if (!result) { 565 // If we have to return zero, there is no way around clearing tos_. 566 __ Set(tos_, Immediate(0)); 567 } else if (!tos_.is(argument)) { 568 // If we have to return non-zero, we can re-use the argument if it is the 569 // same register as the result, because we never see Smi-zero here. 570 __ Set(tos_, Immediate(1)); 571 } 572 __ ret(1 * kPointerSize); 573 __ bind(&different_value); 574 } 575 } 576 577 578 void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { 579 __ pop(ecx); // Get return address, operand is now on top of stack. 580 __ push(Immediate(Smi::FromInt(tos_.code()))); 581 __ push(Immediate(Smi::FromInt(types_.ToByte()))); 582 __ push(ecx); // Push return address. 583 // Patch the caller to an appropriate specialized stub and return the 584 // operation result to the caller of the stub. 585 __ TailCallExternalReference( 586 ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()), 587 3, 588 1); 589 } 590 591 592 class FloatingPointHelper : public AllStatic { 593 public: 594 enum ArgLocation { 595 ARGS_ON_STACK, 596 ARGS_IN_REGISTERS 597 }; 598 599 // Code pattern for loading a floating point value. Input value must 600 // be either a smi or a heap number object (fp value). Requirements: 601 // operand in register number. Returns operand as floating point number 602 // on FPU stack. 603 static void LoadFloatOperand(MacroAssembler* masm, Register number); 604 605 // Code pattern for loading floating point values. Input values must 606 // be either smi or heap number objects (fp values). Requirements: 607 // operand_1 on TOS+1 or in edx, operand_2 on TOS+2 or in eax. 608 // Returns operands as floating point numbers on FPU stack. 609 static void LoadFloatOperands(MacroAssembler* masm, 610 Register scratch, 611 ArgLocation arg_location = ARGS_ON_STACK); 612 613 // Similar to LoadFloatOperand but assumes that both operands are smis. 614 // Expects operands in edx, eax. 615 static void LoadFloatSmis(MacroAssembler* masm, Register scratch); 616 617 // Test if operands are smi or number objects (fp). Requirements: 618 // operand_1 in eax, operand_2 in edx; falls through on float 619 // operands, jumps to the non_float label otherwise. 620 static void CheckFloatOperands(MacroAssembler* masm, 621 Label* non_float, 622 Register scratch); 623 624 // Checks that the two floating point numbers on top of the FPU stack 625 // have int32 values. 626 static void CheckFloatOperandsAreInt32(MacroAssembler* masm, 627 Label* non_int32); 628 629 // Takes the operands in edx and eax and loads them as integers in eax 630 // and ecx. 631 static void LoadUnknownsAsIntegers(MacroAssembler* masm, 632 bool use_sse3, 633 Label* operand_conversion_failure); 634 635 // Must only be called after LoadUnknownsAsIntegers. Assumes that the 636 // operands are pushed on the stack, and that their conversions to int32 637 // are in eax and ecx. Checks that the original numbers were in the int32 638 // range. 639 static void CheckLoadedIntegersWereInt32(MacroAssembler* masm, 640 bool use_sse3, 641 Label* not_int32); 642 643 // Assumes that operands are smis or heap numbers and loads them 644 // into xmm0 and xmm1. Operands are in edx and eax. 645 // Leaves operands unchanged. 646 static void LoadSSE2Operands(MacroAssembler* masm); 647 648 // Test if operands are numbers (smi or HeapNumber objects), and load 649 // them into xmm0 and xmm1 if they are. Jump to label not_numbers if 650 // either operand is not a number. Operands are in edx and eax. 651 // Leaves operands unchanged. 652 static void LoadSSE2Operands(MacroAssembler* masm, Label* not_numbers); 653 654 // Similar to LoadSSE2Operands but assumes that both operands are smis. 655 // Expects operands in edx, eax. 656 static void LoadSSE2Smis(MacroAssembler* masm, Register scratch); 657 658 // Checks that the two floating point numbers loaded into xmm0 and xmm1 659 // have int32 values. 660 static void CheckSSE2OperandsAreInt32(MacroAssembler* masm, 661 Label* non_int32, 662 Register scratch); 663 }; 664 665 666 // Get the integer part of a heap number. Surprisingly, all this bit twiddling 667 // is faster than using the built-in instructions on floating point registers. 668 // Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the 669 // trashed registers. 670 static void IntegerConvert(MacroAssembler* masm, 671 Register source, 672 bool use_sse3, 673 Label* conversion_failure) { 674 ASSERT(!source.is(ecx) && !source.is(edi) && !source.is(ebx)); 675 Label done, right_exponent, normal_exponent; 676 Register scratch = ebx; 677 Register scratch2 = edi; 678 // Get exponent word. 679 __ mov(scratch, FieldOperand(source, HeapNumber::kExponentOffset)); 680 // Get exponent alone in scratch2. 681 __ mov(scratch2, scratch); 682 __ and_(scratch2, HeapNumber::kExponentMask); 683 if (use_sse3) { 684 CpuFeatures::Scope scope(SSE3); 685 // Check whether the exponent is too big for a 64 bit signed integer. 686 static const uint32_t kTooBigExponent = 687 (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift; 688 __ cmp(scratch2, Immediate(kTooBigExponent)); 689 __ j(greater_equal, conversion_failure); 690 // Load x87 register with heap number. 691 __ fld_d(FieldOperand(source, HeapNumber::kValueOffset)); 692 // Reserve space for 64 bit answer. 693 __ sub(esp, Immediate(sizeof(uint64_t))); // Nolint. 694 // Do conversion, which cannot fail because we checked the exponent. 695 __ fisttp_d(Operand(esp, 0)); 696 __ mov(ecx, Operand(esp, 0)); // Load low word of answer into ecx. 697 __ add(esp, Immediate(sizeof(uint64_t))); // Nolint. 698 } else { 699 // Load ecx with zero. We use this either for the final shift or 700 // for the answer. 701 __ xor_(ecx, ecx); 702 // Check whether the exponent matches a 32 bit signed int that cannot be 703 // represented by a Smi. A non-smi 32 bit integer is 1.xxx * 2^30 so the 704 // exponent is 30 (biased). This is the exponent that we are fastest at and 705 // also the highest exponent we can handle here. 706 const uint32_t non_smi_exponent = 707 (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift; 708 __ cmp(scratch2, Immediate(non_smi_exponent)); 709 // If we have a match of the int32-but-not-Smi exponent then skip some 710 // logic. 711 __ j(equal, &right_exponent, Label::kNear); 712 // If the exponent is higher than that then go to slow case. This catches 713 // numbers that don't fit in a signed int32, infinities and NaNs. 714 __ j(less, &normal_exponent, Label::kNear); 715 716 { 717 // Handle a big exponent. The only reason we have this code is that the 718 // >>> operator has a tendency to generate numbers with an exponent of 31. 719 const uint32_t big_non_smi_exponent = 720 (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift; 721 __ cmp(scratch2, Immediate(big_non_smi_exponent)); 722 __ j(not_equal, conversion_failure); 723 // We have the big exponent, typically from >>>. This means the number is 724 // in the range 2^31 to 2^32 - 1. Get the top bits of the mantissa. 725 __ mov(scratch2, scratch); 726 __ and_(scratch2, HeapNumber::kMantissaMask); 727 // Put back the implicit 1. 728 __ or_(scratch2, 1 << HeapNumber::kExponentShift); 729 // Shift up the mantissa bits to take up the space the exponent used to 730 // take. We just orred in the implicit bit so that took care of one and 731 // we want to use the full unsigned range so we subtract 1 bit from the 732 // shift distance. 733 const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 1; 734 __ shl(scratch2, big_shift_distance); 735 // Get the second half of the double. 736 __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset)); 737 // Shift down 21 bits to get the most significant 11 bits or the low 738 // mantissa word. 739 __ shr(ecx, 32 - big_shift_distance); 740 __ or_(ecx, scratch2); 741 // We have the answer in ecx, but we may need to negate it. 742 __ test(scratch, scratch); 743 __ j(positive, &done, Label::kNear); 744 __ neg(ecx); 745 __ jmp(&done, Label::kNear); 746 } 747 748 __ bind(&normal_exponent); 749 // Exponent word in scratch, exponent part of exponent word in scratch2. 750 // Zero in ecx. 751 // We know the exponent is smaller than 30 (biased). If it is less than 752 // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, i.e. 753 // it rounds to zero. 754 const uint32_t zero_exponent = 755 (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift; 756 __ sub(scratch2, Immediate(zero_exponent)); 757 // ecx already has a Smi zero. 758 __ j(less, &done, Label::kNear); 759 760 // We have a shifted exponent between 0 and 30 in scratch2. 761 __ shr(scratch2, HeapNumber::kExponentShift); 762 __ mov(ecx, Immediate(30)); 763 __ sub(ecx, scratch2); 764 765 __ bind(&right_exponent); 766 // Here ecx is the shift, scratch is the exponent word. 767 // Get the top bits of the mantissa. 768 __ and_(scratch, HeapNumber::kMantissaMask); 769 // Put back the implicit 1. 770 __ or_(scratch, 1 << HeapNumber::kExponentShift); 771 // Shift up the mantissa bits to take up the space the exponent used to 772 // take. We have kExponentShift + 1 significant bits int he low end of the 773 // word. Shift them to the top bits. 774 const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2; 775 __ shl(scratch, shift_distance); 776 // Get the second half of the double. For some exponents we don't 777 // actually need this because the bits get shifted out again, but 778 // it's probably slower to test than just to do it. 779 __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset)); 780 // Shift down 22 bits to get the most significant 10 bits or the low 781 // mantissa word. 782 __ shr(scratch2, 32 - shift_distance); 783 __ or_(scratch2, scratch); 784 // Move down according to the exponent. 785 __ shr_cl(scratch2); 786 // Now the unsigned answer is in scratch2. We need to move it to ecx and 787 // we may need to fix the sign. 788 Label negative; 789 __ xor_(ecx, ecx); 790 __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset)); 791 __ j(greater, &negative, Label::kNear); 792 __ mov(ecx, scratch2); 793 __ jmp(&done, Label::kNear); 794 __ bind(&negative); 795 __ sub(ecx, scratch2); 796 __ bind(&done); 797 } 798 } 799 800 801 void UnaryOpStub::PrintName(StringStream* stream) { 802 const char* op_name = Token::Name(op_); 803 const char* overwrite_name = NULL; // Make g++ happy. 804 switch (mode_) { 805 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; 806 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; 807 } 808 stream->Add("UnaryOpStub_%s_%s_%s", 809 op_name, 810 overwrite_name, 811 UnaryOpIC::GetName(operand_type_)); 812 } 813 814 815 // TODO(svenpanne): Use virtual functions instead of switch. 816 void UnaryOpStub::Generate(MacroAssembler* masm) { 817 switch (operand_type_) { 818 case UnaryOpIC::UNINITIALIZED: 819 GenerateTypeTransition(masm); 820 break; 821 case UnaryOpIC::SMI: 822 GenerateSmiStub(masm); 823 break; 824 case UnaryOpIC::HEAP_NUMBER: 825 GenerateHeapNumberStub(masm); 826 break; 827 case UnaryOpIC::GENERIC: 828 GenerateGenericStub(masm); 829 break; 830 } 831 } 832 833 834 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 835 __ pop(ecx); // Save return address. 836 837 __ push(eax); // the operand 838 __ push(Immediate(Smi::FromInt(op_))); 839 __ push(Immediate(Smi::FromInt(mode_))); 840 __ push(Immediate(Smi::FromInt(operand_type_))); 841 842 __ push(ecx); // Push return address. 843 844 // Patch the caller to an appropriate specialized stub and return the 845 // operation result to the caller of the stub. 846 __ TailCallExternalReference( 847 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); 848 } 849 850 851 // TODO(svenpanne): Use virtual functions instead of switch. 852 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 853 switch (op_) { 854 case Token::SUB: 855 GenerateSmiStubSub(masm); 856 break; 857 case Token::BIT_NOT: 858 GenerateSmiStubBitNot(masm); 859 break; 860 default: 861 UNREACHABLE(); 862 } 863 } 864 865 866 void UnaryOpStub::GenerateSmiStubSub(MacroAssembler* masm) { 867 Label non_smi, undo, slow; 868 GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, 869 Label::kNear, Label::kNear, Label::kNear); 870 __ bind(&undo); 871 GenerateSmiCodeUndo(masm); 872 __ bind(&non_smi); 873 __ bind(&slow); 874 GenerateTypeTransition(masm); 875 } 876 877 878 void UnaryOpStub::GenerateSmiStubBitNot(MacroAssembler* masm) { 879 Label non_smi; 880 GenerateSmiCodeBitNot(masm, &non_smi); 881 __ bind(&non_smi); 882 GenerateTypeTransition(masm); 883 } 884 885 886 void UnaryOpStub::GenerateSmiCodeSub(MacroAssembler* masm, 887 Label* non_smi, 888 Label* undo, 889 Label* slow, 890 Label::Distance non_smi_near, 891 Label::Distance undo_near, 892 Label::Distance slow_near) { 893 // Check whether the value is a smi. 894 __ JumpIfNotSmi(eax, non_smi, non_smi_near); 895 896 // We can't handle -0 with smis, so use a type transition for that case. 897 __ test(eax, eax); 898 __ j(zero, slow, slow_near); 899 900 // Try optimistic subtraction '0 - value', saving operand in eax for undo. 901 __ mov(edx, eax); 902 __ Set(eax, Immediate(0)); 903 __ sub(eax, edx); 904 __ j(overflow, undo, undo_near); 905 __ ret(0); 906 } 907 908 909 void UnaryOpStub::GenerateSmiCodeBitNot( 910 MacroAssembler* masm, 911 Label* non_smi, 912 Label::Distance non_smi_near) { 913 // Check whether the value is a smi. 914 __ JumpIfNotSmi(eax, non_smi, non_smi_near); 915 916 // Flip bits and revert inverted smi-tag. 917 __ not_(eax); 918 __ and_(eax, ~kSmiTagMask); 919 __ ret(0); 920 } 921 922 923 void UnaryOpStub::GenerateSmiCodeUndo(MacroAssembler* masm) { 924 __ mov(eax, edx); 925 } 926 927 928 // TODO(svenpanne): Use virtual functions instead of switch. 929 void UnaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 930 switch (op_) { 931 case Token::SUB: 932 GenerateHeapNumberStubSub(masm); 933 break; 934 case Token::BIT_NOT: 935 GenerateHeapNumberStubBitNot(masm); 936 break; 937 default: 938 UNREACHABLE(); 939 } 940 } 941 942 943 void UnaryOpStub::GenerateHeapNumberStubSub(MacroAssembler* masm) { 944 Label non_smi, undo, slow, call_builtin; 945 GenerateSmiCodeSub(masm, &non_smi, &undo, &call_builtin, Label::kNear); 946 __ bind(&non_smi); 947 GenerateHeapNumberCodeSub(masm, &slow); 948 __ bind(&undo); 949 GenerateSmiCodeUndo(masm); 950 __ bind(&slow); 951 GenerateTypeTransition(masm); 952 __ bind(&call_builtin); 953 GenerateGenericCodeFallback(masm); 954 } 955 956 957 void UnaryOpStub::GenerateHeapNumberStubBitNot( 958 MacroAssembler* masm) { 959 Label non_smi, slow; 960 GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); 961 __ bind(&non_smi); 962 GenerateHeapNumberCodeBitNot(masm, &slow); 963 __ bind(&slow); 964 GenerateTypeTransition(masm); 965 } 966 967 968 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm, 969 Label* slow) { 970 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); 971 __ cmp(edx, masm->isolate()->factory()->heap_number_map()); 972 __ j(not_equal, slow); 973 974 if (mode_ == UNARY_OVERWRITE) { 975 __ xor_(FieldOperand(eax, HeapNumber::kExponentOffset), 976 Immediate(HeapNumber::kSignMask)); // Flip sign. 977 } else { 978 __ mov(edx, eax); 979 // edx: operand 980 981 Label slow_allocate_heapnumber, heapnumber_allocated; 982 __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber); 983 __ jmp(&heapnumber_allocated, Label::kNear); 984 985 __ bind(&slow_allocate_heapnumber); 986 { 987 FrameScope scope(masm, StackFrame::INTERNAL); 988 __ push(edx); 989 __ CallRuntime(Runtime::kNumberAlloc, 0); 990 __ pop(edx); 991 } 992 993 __ bind(&heapnumber_allocated); 994 // eax: allocated 'empty' number 995 __ mov(ecx, FieldOperand(edx, HeapNumber::kExponentOffset)); 996 __ xor_(ecx, HeapNumber::kSignMask); // Flip sign. 997 __ mov(FieldOperand(eax, HeapNumber::kExponentOffset), ecx); 998 __ mov(ecx, FieldOperand(edx, HeapNumber::kMantissaOffset)); 999 __ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx); 1000 } 1001 __ ret(0); 1002 } 1003 1004 1005 void UnaryOpStub::GenerateHeapNumberCodeBitNot(MacroAssembler* masm, 1006 Label* slow) { 1007 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); 1008 __ cmp(edx, masm->isolate()->factory()->heap_number_map()); 1009 __ j(not_equal, slow); 1010 1011 // Convert the heap number in eax to an untagged integer in ecx. 1012 IntegerConvert(masm, eax, CpuFeatures::IsSupported(SSE3), slow); 1013 1014 // Do the bitwise operation and check if the result fits in a smi. 1015 Label try_float; 1016 __ not_(ecx); 1017 __ cmp(ecx, 0xc0000000); 1018 __ j(sign, &try_float, Label::kNear); 1019 1020 // Tag the result as a smi and we're done. 1021 STATIC_ASSERT(kSmiTagSize == 1); 1022 __ lea(eax, Operand(ecx, times_2, kSmiTag)); 1023 __ ret(0); 1024 1025 // Try to store the result in a heap number. 1026 __ bind(&try_float); 1027 if (mode_ == UNARY_NO_OVERWRITE) { 1028 Label slow_allocate_heapnumber, heapnumber_allocated; 1029 __ mov(ebx, eax); 1030 __ AllocateHeapNumber(eax, edx, edi, &slow_allocate_heapnumber); 1031 __ jmp(&heapnumber_allocated); 1032 1033 __ bind(&slow_allocate_heapnumber); 1034 { 1035 FrameScope scope(masm, StackFrame::INTERNAL); 1036 // Push the original HeapNumber on the stack. The integer value can't 1037 // be stored since it's untagged and not in the smi range (so we can't 1038 // smi-tag it). We'll recalculate the value after the GC instead. 1039 __ push(ebx); 1040 __ CallRuntime(Runtime::kNumberAlloc, 0); 1041 // New HeapNumber is in eax. 1042 __ pop(edx); 1043 } 1044 // IntegerConvert uses ebx and edi as scratch registers. 1045 // This conversion won't go slow-case. 1046 IntegerConvert(masm, edx, CpuFeatures::IsSupported(SSE3), slow); 1047 __ not_(ecx); 1048 1049 __ bind(&heapnumber_allocated); 1050 } 1051 if (CpuFeatures::IsSupported(SSE2)) { 1052 CpuFeatures::Scope use_sse2(SSE2); 1053 __ cvtsi2sd(xmm0, ecx); 1054 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1055 } else { 1056 __ push(ecx); 1057 __ fild_s(Operand(esp, 0)); 1058 __ pop(ecx); 1059 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1060 } 1061 __ ret(0); 1062 } 1063 1064 1065 // TODO(svenpanne): Use virtual functions instead of switch. 1066 void UnaryOpStub::GenerateGenericStub(MacroAssembler* masm) { 1067 switch (op_) { 1068 case Token::SUB: 1069 GenerateGenericStubSub(masm); 1070 break; 1071 case Token::BIT_NOT: 1072 GenerateGenericStubBitNot(masm); 1073 break; 1074 default: 1075 UNREACHABLE(); 1076 } 1077 } 1078 1079 1080 void UnaryOpStub::GenerateGenericStubSub(MacroAssembler* masm) { 1081 Label non_smi, undo, slow; 1082 GenerateSmiCodeSub(masm, &non_smi, &undo, &slow, Label::kNear); 1083 __ bind(&non_smi); 1084 GenerateHeapNumberCodeSub(masm, &slow); 1085 __ bind(&undo); 1086 GenerateSmiCodeUndo(masm); 1087 __ bind(&slow); 1088 GenerateGenericCodeFallback(masm); 1089 } 1090 1091 1092 void UnaryOpStub::GenerateGenericStubBitNot(MacroAssembler* masm) { 1093 Label non_smi, slow; 1094 GenerateSmiCodeBitNot(masm, &non_smi, Label::kNear); 1095 __ bind(&non_smi); 1096 GenerateHeapNumberCodeBitNot(masm, &slow); 1097 __ bind(&slow); 1098 GenerateGenericCodeFallback(masm); 1099 } 1100 1101 1102 void UnaryOpStub::GenerateGenericCodeFallback(MacroAssembler* masm) { 1103 // Handle the slow case by jumping to the corresponding JavaScript builtin. 1104 __ pop(ecx); // pop return address. 1105 __ push(eax); 1106 __ push(ecx); // push return address 1107 switch (op_) { 1108 case Token::SUB: 1109 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_FUNCTION); 1110 break; 1111 case Token::BIT_NOT: 1112 __ InvokeBuiltin(Builtins::BIT_NOT, JUMP_FUNCTION); 1113 break; 1114 default: 1115 UNREACHABLE(); 1116 } 1117 } 1118 1119 1120 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { 1121 __ pop(ecx); // Save return address. 1122 __ push(edx); 1123 __ push(eax); 1124 // Left and right arguments are now on top. 1125 // Push this stub's key. Although the operation and the type info are 1126 // encoded into the key, the encoding is opaque, so push them too. 1127 __ push(Immediate(Smi::FromInt(MinorKey()))); 1128 __ push(Immediate(Smi::FromInt(op_))); 1129 __ push(Immediate(Smi::FromInt(operands_type_))); 1130 1131 __ push(ecx); // Push return address. 1132 1133 // Patch the caller to an appropriate specialized stub and return the 1134 // operation result to the caller of the stub. 1135 __ TailCallExternalReference( 1136 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), 1137 masm->isolate()), 1138 5, 1139 1); 1140 } 1141 1142 1143 // Prepare for a type transition runtime call when the args are already on 1144 // the stack, under the return address. 1145 void BinaryOpStub::GenerateTypeTransitionWithSavedArgs(MacroAssembler* masm) { 1146 __ pop(ecx); // Save return address. 1147 // Left and right arguments are already on top of the stack. 1148 // Push this stub's key. Although the operation and the type info are 1149 // encoded into the key, the encoding is opaque, so push them too. 1150 __ push(Immediate(Smi::FromInt(MinorKey()))); 1151 __ push(Immediate(Smi::FromInt(op_))); 1152 __ push(Immediate(Smi::FromInt(operands_type_))); 1153 1154 __ push(ecx); // Push return address. 1155 1156 // Patch the caller to an appropriate specialized stub and return the 1157 // operation result to the caller of the stub. 1158 __ TailCallExternalReference( 1159 ExternalReference(IC_Utility(IC::kBinaryOp_Patch), 1160 masm->isolate()), 1161 5, 1162 1); 1163 } 1164 1165 1166 void BinaryOpStub::Generate(MacroAssembler* masm) { 1167 // Explicitly allow generation of nested stubs. It is safe here because 1168 // generation code does not use any raw pointers. 1169 AllowStubCallsScope allow_stub_calls(masm, true); 1170 1171 switch (operands_type_) { 1172 case BinaryOpIC::UNINITIALIZED: 1173 GenerateTypeTransition(masm); 1174 break; 1175 case BinaryOpIC::SMI: 1176 GenerateSmiStub(masm); 1177 break; 1178 case BinaryOpIC::INT32: 1179 GenerateInt32Stub(masm); 1180 break; 1181 case BinaryOpIC::HEAP_NUMBER: 1182 GenerateHeapNumberStub(masm); 1183 break; 1184 case BinaryOpIC::ODDBALL: 1185 GenerateOddballStub(masm); 1186 break; 1187 case BinaryOpIC::BOTH_STRING: 1188 GenerateBothStringStub(masm); 1189 break; 1190 case BinaryOpIC::STRING: 1191 GenerateStringStub(masm); 1192 break; 1193 case BinaryOpIC::GENERIC: 1194 GenerateGeneric(masm); 1195 break; 1196 default: 1197 UNREACHABLE(); 1198 } 1199 } 1200 1201 1202 void BinaryOpStub::PrintName(StringStream* stream) { 1203 const char* op_name = Token::Name(op_); 1204 const char* overwrite_name; 1205 switch (mode_) { 1206 case NO_OVERWRITE: overwrite_name = "Alloc"; break; 1207 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; 1208 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; 1209 default: overwrite_name = "UnknownOverwrite"; break; 1210 } 1211 stream->Add("BinaryOpStub_%s_%s_%s", 1212 op_name, 1213 overwrite_name, 1214 BinaryOpIC::GetName(operands_type_)); 1215 } 1216 1217 1218 void BinaryOpStub::GenerateSmiCode( 1219 MacroAssembler* masm, 1220 Label* slow, 1221 SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { 1222 // 1. Move arguments into edx, eax except for DIV and MOD, which need the 1223 // dividend in eax and edx free for the division. Use eax, ebx for those. 1224 Comment load_comment(masm, "-- Load arguments"); 1225 Register left = edx; 1226 Register right = eax; 1227 if (op_ == Token::DIV || op_ == Token::MOD) { 1228 left = eax; 1229 right = ebx; 1230 __ mov(ebx, eax); 1231 __ mov(eax, edx); 1232 } 1233 1234 1235 // 2. Prepare the smi check of both operands by oring them together. 1236 Comment smi_check_comment(masm, "-- Smi check arguments"); 1237 Label not_smis; 1238 Register combined = ecx; 1239 ASSERT(!left.is(combined) && !right.is(combined)); 1240 switch (op_) { 1241 case Token::BIT_OR: 1242 // Perform the operation into eax and smi check the result. Preserve 1243 // eax in case the result is not a smi. 1244 ASSERT(!left.is(ecx) && !right.is(ecx)); 1245 __ mov(ecx, right); 1246 __ or_(right, left); // Bitwise or is commutative. 1247 combined = right; 1248 break; 1249 1250 case Token::BIT_XOR: 1251 case Token::BIT_AND: 1252 case Token::ADD: 1253 case Token::SUB: 1254 case Token::MUL: 1255 case Token::DIV: 1256 case Token::MOD: 1257 __ mov(combined, right); 1258 __ or_(combined, left); 1259 break; 1260 1261 case Token::SHL: 1262 case Token::SAR: 1263 case Token::SHR: 1264 // Move the right operand into ecx for the shift operation, use eax 1265 // for the smi check register. 1266 ASSERT(!left.is(ecx) && !right.is(ecx)); 1267 __ mov(ecx, right); 1268 __ or_(right, left); 1269 combined = right; 1270 break; 1271 1272 default: 1273 break; 1274 } 1275 1276 // 3. Perform the smi check of the operands. 1277 STATIC_ASSERT(kSmiTag == 0); // Adjust zero check if not the case. 1278 __ JumpIfNotSmi(combined, ¬_smis); 1279 1280 // 4. Operands are both smis, perform the operation leaving the result in 1281 // eax and check the result if necessary. 1282 Comment perform_smi(masm, "-- Perform smi operation"); 1283 Label use_fp_on_smis; 1284 switch (op_) { 1285 case Token::BIT_OR: 1286 // Nothing to do. 1287 break; 1288 1289 case Token::BIT_XOR: 1290 ASSERT(right.is(eax)); 1291 __ xor_(right, left); // Bitwise xor is commutative. 1292 break; 1293 1294 case Token::BIT_AND: 1295 ASSERT(right.is(eax)); 1296 __ and_(right, left); // Bitwise and is commutative. 1297 break; 1298 1299 case Token::SHL: 1300 // Remove tags from operands (but keep sign). 1301 __ SmiUntag(left); 1302 __ SmiUntag(ecx); 1303 // Perform the operation. 1304 __ shl_cl(left); 1305 // Check that the *signed* result fits in a smi. 1306 __ cmp(left, 0xc0000000); 1307 __ j(sign, &use_fp_on_smis); 1308 // Tag the result and store it in register eax. 1309 __ SmiTag(left); 1310 __ mov(eax, left); 1311 break; 1312 1313 case Token::SAR: 1314 // Remove tags from operands (but keep sign). 1315 __ SmiUntag(left); 1316 __ SmiUntag(ecx); 1317 // Perform the operation. 1318 __ sar_cl(left); 1319 // Tag the result and store it in register eax. 1320 __ SmiTag(left); 1321 __ mov(eax, left); 1322 break; 1323 1324 case Token::SHR: 1325 // Remove tags from operands (but keep sign). 1326 __ SmiUntag(left); 1327 __ SmiUntag(ecx); 1328 // Perform the operation. 1329 __ shr_cl(left); 1330 // Check that the *unsigned* result fits in a smi. 1331 // Neither of the two high-order bits can be set: 1332 // - 0x80000000: high bit would be lost when smi tagging. 1333 // - 0x40000000: this number would convert to negative when 1334 // Smi tagging these two cases can only happen with shifts 1335 // by 0 or 1 when handed a valid smi. 1336 __ test(left, Immediate(0xc0000000)); 1337 __ j(not_zero, &use_fp_on_smis); 1338 // Tag the result and store it in register eax. 1339 __ SmiTag(left); 1340 __ mov(eax, left); 1341 break; 1342 1343 case Token::ADD: 1344 ASSERT(right.is(eax)); 1345 __ add(right, left); // Addition is commutative. 1346 __ j(overflow, &use_fp_on_smis); 1347 break; 1348 1349 case Token::SUB: 1350 __ sub(left, right); 1351 __ j(overflow, &use_fp_on_smis); 1352 __ mov(eax, left); 1353 break; 1354 1355 case Token::MUL: 1356 // If the smi tag is 0 we can just leave the tag on one operand. 1357 STATIC_ASSERT(kSmiTag == 0); // Adjust code below if not the case. 1358 // We can't revert the multiplication if the result is not a smi 1359 // so save the right operand. 1360 __ mov(ebx, right); 1361 // Remove tag from one of the operands (but keep sign). 1362 __ SmiUntag(right); 1363 // Do multiplication. 1364 __ imul(right, left); // Multiplication is commutative. 1365 __ j(overflow, &use_fp_on_smis); 1366 // Check for negative zero result. Use combined = left | right. 1367 __ NegativeZeroTest(right, combined, &use_fp_on_smis); 1368 break; 1369 1370 case Token::DIV: 1371 // We can't revert the division if the result is not a smi so 1372 // save the left operand. 1373 __ mov(edi, left); 1374 // Check for 0 divisor. 1375 __ test(right, right); 1376 __ j(zero, &use_fp_on_smis); 1377 // Sign extend left into edx:eax. 1378 ASSERT(left.is(eax)); 1379 __ cdq(); 1380 // Divide edx:eax by right. 1381 __ idiv(right); 1382 // Check for the corner case of dividing the most negative smi by 1383 // -1. We cannot use the overflow flag, since it is not set by idiv 1384 // instruction. 1385 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1); 1386 __ cmp(eax, 0x40000000); 1387 __ j(equal, &use_fp_on_smis); 1388 // Check for negative zero result. Use combined = left | right. 1389 __ NegativeZeroTest(eax, combined, &use_fp_on_smis); 1390 // Check that the remainder is zero. 1391 __ test(edx, edx); 1392 __ j(not_zero, &use_fp_on_smis); 1393 // Tag the result and store it in register eax. 1394 __ SmiTag(eax); 1395 break; 1396 1397 case Token::MOD: 1398 // Check for 0 divisor. 1399 __ test(right, right); 1400 __ j(zero, ¬_smis); 1401 1402 // Sign extend left into edx:eax. 1403 ASSERT(left.is(eax)); 1404 __ cdq(); 1405 // Divide edx:eax by right. 1406 __ idiv(right); 1407 // Check for negative zero result. Use combined = left | right. 1408 __ NegativeZeroTest(edx, combined, slow); 1409 // Move remainder to register eax. 1410 __ mov(eax, edx); 1411 break; 1412 1413 default: 1414 UNREACHABLE(); 1415 } 1416 1417 // 5. Emit return of result in eax. Some operations have registers pushed. 1418 switch (op_) { 1419 case Token::ADD: 1420 case Token::SUB: 1421 case Token::MUL: 1422 case Token::DIV: 1423 __ ret(0); 1424 break; 1425 case Token::MOD: 1426 case Token::BIT_OR: 1427 case Token::BIT_AND: 1428 case Token::BIT_XOR: 1429 case Token::SAR: 1430 case Token::SHL: 1431 case Token::SHR: 1432 __ ret(2 * kPointerSize); 1433 break; 1434 default: 1435 UNREACHABLE(); 1436 } 1437 1438 // 6. For some operations emit inline code to perform floating point 1439 // operations on known smis (e.g., if the result of the operation 1440 // overflowed the smi range). 1441 if (allow_heapnumber_results == NO_HEAPNUMBER_RESULTS) { 1442 __ bind(&use_fp_on_smis); 1443 switch (op_) { 1444 // Undo the effects of some operations, and some register moves. 1445 case Token::SHL: 1446 // The arguments are saved on the stack, and only used from there. 1447 break; 1448 case Token::ADD: 1449 // Revert right = right + left. 1450 __ sub(right, left); 1451 break; 1452 case Token::SUB: 1453 // Revert left = left - right. 1454 __ add(left, right); 1455 break; 1456 case Token::MUL: 1457 // Right was clobbered but a copy is in ebx. 1458 __ mov(right, ebx); 1459 break; 1460 case Token::DIV: 1461 // Left was clobbered but a copy is in edi. Right is in ebx for 1462 // division. They should be in eax, ebx for jump to not_smi. 1463 __ mov(eax, edi); 1464 break; 1465 default: 1466 // No other operators jump to use_fp_on_smis. 1467 break; 1468 } 1469 __ jmp(¬_smis); 1470 } else { 1471 ASSERT(allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS); 1472 switch (op_) { 1473 case Token::SHL: 1474 case Token::SHR: { 1475 Comment perform_float(masm, "-- Perform float operation on smis"); 1476 __ bind(&use_fp_on_smis); 1477 // Result we want is in left == edx, so we can put the allocated heap 1478 // number in eax. 1479 __ AllocateHeapNumber(eax, ecx, ebx, slow); 1480 // Store the result in the HeapNumber and return. 1481 // It's OK to overwrite the arguments on the stack because we 1482 // are about to return. 1483 if (op_ == Token::SHR) { 1484 __ mov(Operand(esp, 1 * kPointerSize), left); 1485 __ mov(Operand(esp, 2 * kPointerSize), Immediate(0)); 1486 __ fild_d(Operand(esp, 1 * kPointerSize)); 1487 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1488 } else { 1489 ASSERT_EQ(Token::SHL, op_); 1490 if (CpuFeatures::IsSupported(SSE2)) { 1491 CpuFeatures::Scope use_sse2(SSE2); 1492 __ cvtsi2sd(xmm0, left); 1493 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1494 } else { 1495 __ mov(Operand(esp, 1 * kPointerSize), left); 1496 __ fild_s(Operand(esp, 1 * kPointerSize)); 1497 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1498 } 1499 } 1500 __ ret(2 * kPointerSize); 1501 break; 1502 } 1503 1504 case Token::ADD: 1505 case Token::SUB: 1506 case Token::MUL: 1507 case Token::DIV: { 1508 Comment perform_float(masm, "-- Perform float operation on smis"); 1509 __ bind(&use_fp_on_smis); 1510 // Restore arguments to edx, eax. 1511 switch (op_) { 1512 case Token::ADD: 1513 // Revert right = right + left. 1514 __ sub(right, left); 1515 break; 1516 case Token::SUB: 1517 // Revert left = left - right. 1518 __ add(left, right); 1519 break; 1520 case Token::MUL: 1521 // Right was clobbered but a copy is in ebx. 1522 __ mov(right, ebx); 1523 break; 1524 case Token::DIV: 1525 // Left was clobbered but a copy is in edi. Right is in ebx for 1526 // division. 1527 __ mov(edx, edi); 1528 __ mov(eax, right); 1529 break; 1530 default: UNREACHABLE(); 1531 break; 1532 } 1533 __ AllocateHeapNumber(ecx, ebx, no_reg, slow); 1534 if (CpuFeatures::IsSupported(SSE2)) { 1535 CpuFeatures::Scope use_sse2(SSE2); 1536 FloatingPointHelper::LoadSSE2Smis(masm, ebx); 1537 switch (op_) { 1538 case Token::ADD: __ addsd(xmm0, xmm1); break; 1539 case Token::SUB: __ subsd(xmm0, xmm1); break; 1540 case Token::MUL: __ mulsd(xmm0, xmm1); break; 1541 case Token::DIV: __ divsd(xmm0, xmm1); break; 1542 default: UNREACHABLE(); 1543 } 1544 __ movdbl(FieldOperand(ecx, HeapNumber::kValueOffset), xmm0); 1545 } else { // SSE2 not available, use FPU. 1546 FloatingPointHelper::LoadFloatSmis(masm, ebx); 1547 switch (op_) { 1548 case Token::ADD: __ faddp(1); break; 1549 case Token::SUB: __ fsubp(1); break; 1550 case Token::MUL: __ fmulp(1); break; 1551 case Token::DIV: __ fdivp(1); break; 1552 default: UNREACHABLE(); 1553 } 1554 __ fstp_d(FieldOperand(ecx, HeapNumber::kValueOffset)); 1555 } 1556 __ mov(eax, ecx); 1557 __ ret(0); 1558 break; 1559 } 1560 1561 default: 1562 break; 1563 } 1564 } 1565 1566 // 7. Non-smi operands, fall out to the non-smi code with the operands in 1567 // edx and eax. 1568 Comment done_comment(masm, "-- Enter non-smi code"); 1569 __ bind(¬_smis); 1570 switch (op_) { 1571 case Token::BIT_OR: 1572 case Token::SHL: 1573 case Token::SAR: 1574 case Token::SHR: 1575 // Right operand is saved in ecx and eax was destroyed by the smi 1576 // check. 1577 __ mov(eax, ecx); 1578 break; 1579 1580 case Token::DIV: 1581 case Token::MOD: 1582 // Operands are in eax, ebx at this point. 1583 __ mov(edx, eax); 1584 __ mov(eax, ebx); 1585 break; 1586 1587 default: 1588 break; 1589 } 1590 } 1591 1592 1593 void BinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { 1594 Label call_runtime; 1595 1596 switch (op_) { 1597 case Token::ADD: 1598 case Token::SUB: 1599 case Token::MUL: 1600 case Token::DIV: 1601 break; 1602 case Token::MOD: 1603 case Token::BIT_OR: 1604 case Token::BIT_AND: 1605 case Token::BIT_XOR: 1606 case Token::SAR: 1607 case Token::SHL: 1608 case Token::SHR: 1609 GenerateRegisterArgsPush(masm); 1610 break; 1611 default: 1612 UNREACHABLE(); 1613 } 1614 1615 if (result_type_ == BinaryOpIC::UNINITIALIZED || 1616 result_type_ == BinaryOpIC::SMI) { 1617 GenerateSmiCode(masm, &call_runtime, NO_HEAPNUMBER_RESULTS); 1618 } else { 1619 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 1620 } 1621 __ bind(&call_runtime); 1622 switch (op_) { 1623 case Token::ADD: 1624 case Token::SUB: 1625 case Token::MUL: 1626 case Token::DIV: 1627 GenerateTypeTransition(masm); 1628 break; 1629 case Token::MOD: 1630 case Token::BIT_OR: 1631 case Token::BIT_AND: 1632 case Token::BIT_XOR: 1633 case Token::SAR: 1634 case Token::SHL: 1635 case Token::SHR: 1636 GenerateTypeTransitionWithSavedArgs(masm); 1637 break; 1638 default: 1639 UNREACHABLE(); 1640 } 1641 } 1642 1643 1644 void BinaryOpStub::GenerateStringStub(MacroAssembler* masm) { 1645 ASSERT(operands_type_ == BinaryOpIC::STRING); 1646 ASSERT(op_ == Token::ADD); 1647 // Try to add arguments as strings, otherwise, transition to the generic 1648 // BinaryOpIC type. 1649 GenerateAddStrings(masm); 1650 GenerateTypeTransition(masm); 1651 } 1652 1653 1654 void BinaryOpStub::GenerateBothStringStub(MacroAssembler* masm) { 1655 Label call_runtime; 1656 ASSERT(operands_type_ == BinaryOpIC::BOTH_STRING); 1657 ASSERT(op_ == Token::ADD); 1658 // If both arguments are strings, call the string add stub. 1659 // Otherwise, do a transition. 1660 1661 // Registers containing left and right operands respectively. 1662 Register left = edx; 1663 Register right = eax; 1664 1665 // Test if left operand is a string. 1666 __ JumpIfSmi(left, &call_runtime, Label::kNear); 1667 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); 1668 __ j(above_equal, &call_runtime, Label::kNear); 1669 1670 // Test if right operand is a string. 1671 __ JumpIfSmi(right, &call_runtime, Label::kNear); 1672 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); 1673 __ j(above_equal, &call_runtime, Label::kNear); 1674 1675 StringAddStub string_add_stub(NO_STRING_CHECK_IN_STUB); 1676 GenerateRegisterArgsPush(masm); 1677 __ TailCallStub(&string_add_stub); 1678 1679 __ bind(&call_runtime); 1680 GenerateTypeTransition(masm); 1681 } 1682 1683 1684 void BinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { 1685 Label call_runtime; 1686 ASSERT(operands_type_ == BinaryOpIC::INT32); 1687 1688 // Floating point case. 1689 switch (op_) { 1690 case Token::ADD: 1691 case Token::SUB: 1692 case Token::MUL: 1693 case Token::DIV: { 1694 Label not_floats; 1695 Label not_int32; 1696 if (CpuFeatures::IsSupported(SSE2)) { 1697 CpuFeatures::Scope use_sse2(SSE2); 1698 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1699 FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); 1700 switch (op_) { 1701 case Token::ADD: __ addsd(xmm0, xmm1); break; 1702 case Token::SUB: __ subsd(xmm0, xmm1); break; 1703 case Token::MUL: __ mulsd(xmm0, xmm1); break; 1704 case Token::DIV: __ divsd(xmm0, xmm1); break; 1705 default: UNREACHABLE(); 1706 } 1707 // Check result type if it is currently Int32. 1708 if (result_type_ <= BinaryOpIC::INT32) { 1709 __ cvttsd2si(ecx, Operand(xmm0)); 1710 __ cvtsi2sd(xmm2, ecx); 1711 __ ucomisd(xmm0, xmm2); 1712 __ j(not_zero, ¬_int32); 1713 __ j(carry, ¬_int32); 1714 } 1715 GenerateHeapResultAllocation(masm, &call_runtime); 1716 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1717 __ ret(0); 1718 } else { // SSE2 not available, use FPU. 1719 FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); 1720 FloatingPointHelper::LoadFloatOperands( 1721 masm, 1722 ecx, 1723 FloatingPointHelper::ARGS_IN_REGISTERS); 1724 FloatingPointHelper::CheckFloatOperandsAreInt32(masm, ¬_int32); 1725 switch (op_) { 1726 case Token::ADD: __ faddp(1); break; 1727 case Token::SUB: __ fsubp(1); break; 1728 case Token::MUL: __ fmulp(1); break; 1729 case Token::DIV: __ fdivp(1); break; 1730 default: UNREACHABLE(); 1731 } 1732 Label after_alloc_failure; 1733 GenerateHeapResultAllocation(masm, &after_alloc_failure); 1734 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1735 __ ret(0); 1736 __ bind(&after_alloc_failure); 1737 __ ffree(); 1738 __ jmp(&call_runtime); 1739 } 1740 1741 __ bind(¬_floats); 1742 __ bind(¬_int32); 1743 GenerateTypeTransition(masm); 1744 break; 1745 } 1746 1747 case Token::MOD: { 1748 // For MOD we go directly to runtime in the non-smi case. 1749 break; 1750 } 1751 case Token::BIT_OR: 1752 case Token::BIT_AND: 1753 case Token::BIT_XOR: 1754 case Token::SAR: 1755 case Token::SHL: 1756 case Token::SHR: { 1757 GenerateRegisterArgsPush(masm); 1758 Label not_floats; 1759 Label not_int32; 1760 Label non_smi_result; 1761 /* { 1762 CpuFeatures::Scope use_sse2(SSE2); 1763 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1764 FloatingPointHelper::CheckSSE2OperandsAreInt32(masm, ¬_int32, ecx); 1765 }*/ 1766 FloatingPointHelper::LoadUnknownsAsIntegers(masm, 1767 use_sse3_, 1768 ¬_floats); 1769 FloatingPointHelper::CheckLoadedIntegersWereInt32(masm, use_sse3_, 1770 ¬_int32); 1771 switch (op_) { 1772 case Token::BIT_OR: __ or_(eax, ecx); break; 1773 case Token::BIT_AND: __ and_(eax, ecx); break; 1774 case Token::BIT_XOR: __ xor_(eax, ecx); break; 1775 case Token::SAR: __ sar_cl(eax); break; 1776 case Token::SHL: __ shl_cl(eax); break; 1777 case Token::SHR: __ shr_cl(eax); break; 1778 default: UNREACHABLE(); 1779 } 1780 if (op_ == Token::SHR) { 1781 // Check if result is non-negative and fits in a smi. 1782 __ test(eax, Immediate(0xc0000000)); 1783 __ j(not_zero, &call_runtime); 1784 } else { 1785 // Check if result fits in a smi. 1786 __ cmp(eax, 0xc0000000); 1787 __ j(negative, &non_smi_result, Label::kNear); 1788 } 1789 // Tag smi result and return. 1790 __ SmiTag(eax); 1791 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1792 1793 // All ops except SHR return a signed int32 that we load in 1794 // a HeapNumber. 1795 if (op_ != Token::SHR) { 1796 __ bind(&non_smi_result); 1797 // Allocate a heap number if needed. 1798 __ mov(ebx, eax); // ebx: result 1799 Label skip_allocation; 1800 switch (mode_) { 1801 case OVERWRITE_LEFT: 1802 case OVERWRITE_RIGHT: 1803 // If the operand was an object, we skip the 1804 // allocation of a heap number. 1805 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 1806 1 * kPointerSize : 2 * kPointerSize)); 1807 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 1808 // Fall through! 1809 case NO_OVERWRITE: 1810 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 1811 __ bind(&skip_allocation); 1812 break; 1813 default: UNREACHABLE(); 1814 } 1815 // Store the result in the HeapNumber and return. 1816 if (CpuFeatures::IsSupported(SSE2)) { 1817 CpuFeatures::Scope use_sse2(SSE2); 1818 __ cvtsi2sd(xmm0, ebx); 1819 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1820 } else { 1821 __ mov(Operand(esp, 1 * kPointerSize), ebx); 1822 __ fild_s(Operand(esp, 1 * kPointerSize)); 1823 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1824 } 1825 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 1826 } 1827 1828 __ bind(¬_floats); 1829 __ bind(¬_int32); 1830 GenerateTypeTransitionWithSavedArgs(masm); 1831 break; 1832 } 1833 default: UNREACHABLE(); break; 1834 } 1835 1836 // If an allocation fails, or SHR or MOD hit a hard case, 1837 // use the runtime system to get the correct result. 1838 __ bind(&call_runtime); 1839 1840 switch (op_) { 1841 case Token::ADD: 1842 GenerateRegisterArgsPush(masm); 1843 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 1844 break; 1845 case Token::SUB: 1846 GenerateRegisterArgsPush(masm); 1847 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 1848 break; 1849 case Token::MUL: 1850 GenerateRegisterArgsPush(masm); 1851 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 1852 break; 1853 case Token::DIV: 1854 GenerateRegisterArgsPush(masm); 1855 __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 1856 break; 1857 case Token::MOD: 1858 GenerateRegisterArgsPush(masm); 1859 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 1860 break; 1861 case Token::BIT_OR: 1862 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 1863 break; 1864 case Token::BIT_AND: 1865 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 1866 break; 1867 case Token::BIT_XOR: 1868 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 1869 break; 1870 case Token::SAR: 1871 __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 1872 break; 1873 case Token::SHL: 1874 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 1875 break; 1876 case Token::SHR: 1877 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 1878 break; 1879 default: 1880 UNREACHABLE(); 1881 } 1882 } 1883 1884 1885 void BinaryOpStub::GenerateOddballStub(MacroAssembler* masm) { 1886 if (op_ == Token::ADD) { 1887 // Handle string addition here, because it is the only operation 1888 // that does not do a ToNumber conversion on the operands. 1889 GenerateAddStrings(masm); 1890 } 1891 1892 Factory* factory = masm->isolate()->factory(); 1893 1894 // Convert odd ball arguments to numbers. 1895 Label check, done; 1896 __ cmp(edx, factory->undefined_value()); 1897 __ j(not_equal, &check, Label::kNear); 1898 if (Token::IsBitOp(op_)) { 1899 __ xor_(edx, edx); 1900 } else { 1901 __ mov(edx, Immediate(factory->nan_value())); 1902 } 1903 __ jmp(&done, Label::kNear); 1904 __ bind(&check); 1905 __ cmp(eax, factory->undefined_value()); 1906 __ j(not_equal, &done, Label::kNear); 1907 if (Token::IsBitOp(op_)) { 1908 __ xor_(eax, eax); 1909 } else { 1910 __ mov(eax, Immediate(factory->nan_value())); 1911 } 1912 __ bind(&done); 1913 1914 GenerateHeapNumberStub(masm); 1915 } 1916 1917 1918 void BinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { 1919 Label call_runtime; 1920 1921 // Floating point case. 1922 switch (op_) { 1923 case Token::ADD: 1924 case Token::SUB: 1925 case Token::MUL: 1926 case Token::DIV: { 1927 Label not_floats; 1928 if (CpuFeatures::IsSupported(SSE2)) { 1929 CpuFeatures::Scope use_sse2(SSE2); 1930 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 1931 1932 switch (op_) { 1933 case Token::ADD: __ addsd(xmm0, xmm1); break; 1934 case Token::SUB: __ subsd(xmm0, xmm1); break; 1935 case Token::MUL: __ mulsd(xmm0, xmm1); break; 1936 case Token::DIV: __ divsd(xmm0, xmm1); break; 1937 default: UNREACHABLE(); 1938 } 1939 GenerateHeapResultAllocation(masm, &call_runtime); 1940 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 1941 __ ret(0); 1942 } else { // SSE2 not available, use FPU. 1943 FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); 1944 FloatingPointHelper::LoadFloatOperands( 1945 masm, 1946 ecx, 1947 FloatingPointHelper::ARGS_IN_REGISTERS); 1948 switch (op_) { 1949 case Token::ADD: __ faddp(1); break; 1950 case Token::SUB: __ fsubp(1); break; 1951 case Token::MUL: __ fmulp(1); break; 1952 case Token::DIV: __ fdivp(1); break; 1953 default: UNREACHABLE(); 1954 } 1955 Label after_alloc_failure; 1956 GenerateHeapResultAllocation(masm, &after_alloc_failure); 1957 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 1958 __ ret(0); 1959 __ bind(&after_alloc_failure); 1960 __ ffree(); 1961 __ jmp(&call_runtime); 1962 } 1963 1964 __ bind(¬_floats); 1965 GenerateTypeTransition(masm); 1966 break; 1967 } 1968 1969 case Token::MOD: { 1970 // For MOD we go directly to runtime in the non-smi case. 1971 break; 1972 } 1973 case Token::BIT_OR: 1974 case Token::BIT_AND: 1975 case Token::BIT_XOR: 1976 case Token::SAR: 1977 case Token::SHL: 1978 case Token::SHR: { 1979 GenerateRegisterArgsPush(masm); 1980 Label not_floats; 1981 Label non_smi_result; 1982 FloatingPointHelper::LoadUnknownsAsIntegers(masm, 1983 use_sse3_, 1984 ¬_floats); 1985 switch (op_) { 1986 case Token::BIT_OR: __ or_(eax, ecx); break; 1987 case Token::BIT_AND: __ and_(eax, ecx); break; 1988 case Token::BIT_XOR: __ xor_(eax, ecx); break; 1989 case Token::SAR: __ sar_cl(eax); break; 1990 case Token::SHL: __ shl_cl(eax); break; 1991 case Token::SHR: __ shr_cl(eax); break; 1992 default: UNREACHABLE(); 1993 } 1994 if (op_ == Token::SHR) { 1995 // Check if result is non-negative and fits in a smi. 1996 __ test(eax, Immediate(0xc0000000)); 1997 __ j(not_zero, &call_runtime); 1998 } else { 1999 // Check if result fits in a smi. 2000 __ cmp(eax, 0xc0000000); 2001 __ j(negative, &non_smi_result, Label::kNear); 2002 } 2003 // Tag smi result and return. 2004 __ SmiTag(eax); 2005 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 2006 2007 // All ops except SHR return a signed int32 that we load in 2008 // a HeapNumber. 2009 if (op_ != Token::SHR) { 2010 __ bind(&non_smi_result); 2011 // Allocate a heap number if needed. 2012 __ mov(ebx, eax); // ebx: result 2013 Label skip_allocation; 2014 switch (mode_) { 2015 case OVERWRITE_LEFT: 2016 case OVERWRITE_RIGHT: 2017 // If the operand was an object, we skip the 2018 // allocation of a heap number. 2019 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 2020 1 * kPointerSize : 2 * kPointerSize)); 2021 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 2022 // Fall through! 2023 case NO_OVERWRITE: 2024 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 2025 __ bind(&skip_allocation); 2026 break; 2027 default: UNREACHABLE(); 2028 } 2029 // Store the result in the HeapNumber and return. 2030 if (CpuFeatures::IsSupported(SSE2)) { 2031 CpuFeatures::Scope use_sse2(SSE2); 2032 __ cvtsi2sd(xmm0, ebx); 2033 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 2034 } else { 2035 __ mov(Operand(esp, 1 * kPointerSize), ebx); 2036 __ fild_s(Operand(esp, 1 * kPointerSize)); 2037 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2038 } 2039 __ ret(2 * kPointerSize); // Drop two pushed arguments from the stack. 2040 } 2041 2042 __ bind(¬_floats); 2043 GenerateTypeTransitionWithSavedArgs(masm); 2044 break; 2045 } 2046 default: UNREACHABLE(); break; 2047 } 2048 2049 // If an allocation fails, or SHR or MOD hit a hard case, 2050 // use the runtime system to get the correct result. 2051 __ bind(&call_runtime); 2052 2053 switch (op_) { 2054 case Token::ADD: 2055 GenerateRegisterArgsPush(masm); 2056 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 2057 break; 2058 case Token::SUB: 2059 GenerateRegisterArgsPush(masm); 2060 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 2061 break; 2062 case Token::MUL: 2063 GenerateRegisterArgsPush(masm); 2064 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 2065 break; 2066 case Token::DIV: 2067 GenerateRegisterArgsPush(masm); 2068 __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 2069 break; 2070 case Token::MOD: 2071 GenerateRegisterArgsPush(masm); 2072 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 2073 break; 2074 case Token::BIT_OR: 2075 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 2076 break; 2077 case Token::BIT_AND: 2078 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 2079 break; 2080 case Token::BIT_XOR: 2081 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 2082 break; 2083 case Token::SAR: 2084 __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 2085 break; 2086 case Token::SHL: 2087 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 2088 break; 2089 case Token::SHR: 2090 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 2091 break; 2092 default: 2093 UNREACHABLE(); 2094 } 2095 } 2096 2097 2098 void BinaryOpStub::GenerateGeneric(MacroAssembler* masm) { 2099 Label call_runtime; 2100 2101 Counters* counters = masm->isolate()->counters(); 2102 __ IncrementCounter(counters->generic_binary_stub_calls(), 1); 2103 2104 switch (op_) { 2105 case Token::ADD: 2106 case Token::SUB: 2107 case Token::MUL: 2108 case Token::DIV: 2109 break; 2110 case Token::MOD: 2111 case Token::BIT_OR: 2112 case Token::BIT_AND: 2113 case Token::BIT_XOR: 2114 case Token::SAR: 2115 case Token::SHL: 2116 case Token::SHR: 2117 GenerateRegisterArgsPush(masm); 2118 break; 2119 default: 2120 UNREACHABLE(); 2121 } 2122 2123 GenerateSmiCode(masm, &call_runtime, ALLOW_HEAPNUMBER_RESULTS); 2124 2125 // Floating point case. 2126 switch (op_) { 2127 case Token::ADD: 2128 case Token::SUB: 2129 case Token::MUL: 2130 case Token::DIV: { 2131 Label not_floats; 2132 if (CpuFeatures::IsSupported(SSE2)) { 2133 CpuFeatures::Scope use_sse2(SSE2); 2134 FloatingPointHelper::LoadSSE2Operands(masm, ¬_floats); 2135 2136 switch (op_) { 2137 case Token::ADD: __ addsd(xmm0, xmm1); break; 2138 case Token::SUB: __ subsd(xmm0, xmm1); break; 2139 case Token::MUL: __ mulsd(xmm0, xmm1); break; 2140 case Token::DIV: __ divsd(xmm0, xmm1); break; 2141 default: UNREACHABLE(); 2142 } 2143 GenerateHeapResultAllocation(masm, &call_runtime); 2144 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 2145 __ ret(0); 2146 } else { // SSE2 not available, use FPU. 2147 FloatingPointHelper::CheckFloatOperands(masm, ¬_floats, ebx); 2148 FloatingPointHelper::LoadFloatOperands( 2149 masm, 2150 ecx, 2151 FloatingPointHelper::ARGS_IN_REGISTERS); 2152 switch (op_) { 2153 case Token::ADD: __ faddp(1); break; 2154 case Token::SUB: __ fsubp(1); break; 2155 case Token::MUL: __ fmulp(1); break; 2156 case Token::DIV: __ fdivp(1); break; 2157 default: UNREACHABLE(); 2158 } 2159 Label after_alloc_failure; 2160 GenerateHeapResultAllocation(masm, &after_alloc_failure); 2161 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2162 __ ret(0); 2163 __ bind(&after_alloc_failure); 2164 __ ffree(); 2165 __ jmp(&call_runtime); 2166 } 2167 __ bind(¬_floats); 2168 break; 2169 } 2170 case Token::MOD: { 2171 // For MOD we go directly to runtime in the non-smi case. 2172 break; 2173 } 2174 case Token::BIT_OR: 2175 case Token::BIT_AND: 2176 case Token::BIT_XOR: 2177 case Token::SAR: 2178 case Token::SHL: 2179 case Token::SHR: { 2180 Label non_smi_result; 2181 FloatingPointHelper::LoadUnknownsAsIntegers(masm, 2182 use_sse3_, 2183 &call_runtime); 2184 switch (op_) { 2185 case Token::BIT_OR: __ or_(eax, ecx); break; 2186 case Token::BIT_AND: __ and_(eax, ecx); break; 2187 case Token::BIT_XOR: __ xor_(eax, ecx); break; 2188 case Token::SAR: __ sar_cl(eax); break; 2189 case Token::SHL: __ shl_cl(eax); break; 2190 case Token::SHR: __ shr_cl(eax); break; 2191 default: UNREACHABLE(); 2192 } 2193 if (op_ == Token::SHR) { 2194 // Check if result is non-negative and fits in a smi. 2195 __ test(eax, Immediate(0xc0000000)); 2196 __ j(not_zero, &call_runtime); 2197 } else { 2198 // Check if result fits in a smi. 2199 __ cmp(eax, 0xc0000000); 2200 __ j(negative, &non_smi_result, Label::kNear); 2201 } 2202 // Tag smi result and return. 2203 __ SmiTag(eax); 2204 __ ret(2 * kPointerSize); // Drop the arguments from the stack. 2205 2206 // All ops except SHR return a signed int32 that we load in 2207 // a HeapNumber. 2208 if (op_ != Token::SHR) { 2209 __ bind(&non_smi_result); 2210 // Allocate a heap number if needed. 2211 __ mov(ebx, eax); // ebx: result 2212 Label skip_allocation; 2213 switch (mode_) { 2214 case OVERWRITE_LEFT: 2215 case OVERWRITE_RIGHT: 2216 // If the operand was an object, we skip the 2217 // allocation of a heap number. 2218 __ mov(eax, Operand(esp, mode_ == OVERWRITE_RIGHT ? 2219 1 * kPointerSize : 2 * kPointerSize)); 2220 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 2221 // Fall through! 2222 case NO_OVERWRITE: 2223 __ AllocateHeapNumber(eax, ecx, edx, &call_runtime); 2224 __ bind(&skip_allocation); 2225 break; 2226 default: UNREACHABLE(); 2227 } 2228 // Store the result in the HeapNumber and return. 2229 if (CpuFeatures::IsSupported(SSE2)) { 2230 CpuFeatures::Scope use_sse2(SSE2); 2231 __ cvtsi2sd(xmm0, ebx); 2232 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm0); 2233 } else { 2234 __ mov(Operand(esp, 1 * kPointerSize), ebx); 2235 __ fild_s(Operand(esp, 1 * kPointerSize)); 2236 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2237 } 2238 __ ret(2 * kPointerSize); 2239 } 2240 break; 2241 } 2242 default: UNREACHABLE(); break; 2243 } 2244 2245 // If all else fails, use the runtime system to get the correct 2246 // result. 2247 __ bind(&call_runtime); 2248 switch (op_) { 2249 case Token::ADD: { 2250 GenerateAddStrings(masm); 2251 GenerateRegisterArgsPush(masm); 2252 __ InvokeBuiltin(Builtins::ADD, JUMP_FUNCTION); 2253 break; 2254 } 2255 case Token::SUB: 2256 GenerateRegisterArgsPush(masm); 2257 __ InvokeBuiltin(Builtins::SUB, JUMP_FUNCTION); 2258 break; 2259 case Token::MUL: 2260 GenerateRegisterArgsPush(masm); 2261 __ InvokeBuiltin(Builtins::MUL, JUMP_FUNCTION); 2262 break; 2263 case Token::DIV: 2264 GenerateRegisterArgsPush(masm); 2265 __ InvokeBuiltin(Builtins::DIV, JUMP_FUNCTION); 2266 break; 2267 case Token::MOD: 2268 __ InvokeBuiltin(Builtins::MOD, JUMP_FUNCTION); 2269 break; 2270 case Token::BIT_OR: 2271 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_FUNCTION); 2272 break; 2273 case Token::BIT_AND: 2274 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_FUNCTION); 2275 break; 2276 case Token::BIT_XOR: 2277 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_FUNCTION); 2278 break; 2279 case Token::SAR: 2280 __ InvokeBuiltin(Builtins::SAR, JUMP_FUNCTION); 2281 break; 2282 case Token::SHL: 2283 __ InvokeBuiltin(Builtins::SHL, JUMP_FUNCTION); 2284 break; 2285 case Token::SHR: 2286 __ InvokeBuiltin(Builtins::SHR, JUMP_FUNCTION); 2287 break; 2288 default: 2289 UNREACHABLE(); 2290 } 2291 } 2292 2293 2294 void BinaryOpStub::GenerateAddStrings(MacroAssembler* masm) { 2295 ASSERT(op_ == Token::ADD); 2296 Label left_not_string, call_runtime; 2297 2298 // Registers containing left and right operands respectively. 2299 Register left = edx; 2300 Register right = eax; 2301 2302 // Test if left operand is a string. 2303 __ JumpIfSmi(left, &left_not_string, Label::kNear); 2304 __ CmpObjectType(left, FIRST_NONSTRING_TYPE, ecx); 2305 __ j(above_equal, &left_not_string, Label::kNear); 2306 2307 StringAddStub string_add_left_stub(NO_STRING_CHECK_LEFT_IN_STUB); 2308 GenerateRegisterArgsPush(masm); 2309 __ TailCallStub(&string_add_left_stub); 2310 2311 // Left operand is not a string, test right. 2312 __ bind(&left_not_string); 2313 __ JumpIfSmi(right, &call_runtime, Label::kNear); 2314 __ CmpObjectType(right, FIRST_NONSTRING_TYPE, ecx); 2315 __ j(above_equal, &call_runtime, Label::kNear); 2316 2317 StringAddStub string_add_right_stub(NO_STRING_CHECK_RIGHT_IN_STUB); 2318 GenerateRegisterArgsPush(masm); 2319 __ TailCallStub(&string_add_right_stub); 2320 2321 // Neither argument is a string. 2322 __ bind(&call_runtime); 2323 } 2324 2325 2326 void BinaryOpStub::GenerateHeapResultAllocation( 2327 MacroAssembler* masm, 2328 Label* alloc_failure) { 2329 Label skip_allocation; 2330 OverwriteMode mode = mode_; 2331 switch (mode) { 2332 case OVERWRITE_LEFT: { 2333 // If the argument in edx is already an object, we skip the 2334 // allocation of a heap number. 2335 __ JumpIfNotSmi(edx, &skip_allocation, Label::kNear); 2336 // Allocate a heap number for the result. Keep eax and edx intact 2337 // for the possible runtime call. 2338 __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); 2339 // Now edx can be overwritten losing one of the arguments as we are 2340 // now done and will not need it any more. 2341 __ mov(edx, ebx); 2342 __ bind(&skip_allocation); 2343 // Use object in edx as a result holder 2344 __ mov(eax, edx); 2345 break; 2346 } 2347 case OVERWRITE_RIGHT: 2348 // If the argument in eax is already an object, we skip the 2349 // allocation of a heap number. 2350 __ JumpIfNotSmi(eax, &skip_allocation, Label::kNear); 2351 // Fall through! 2352 case NO_OVERWRITE: 2353 // Allocate a heap number for the result. Keep eax and edx intact 2354 // for the possible runtime call. 2355 __ AllocateHeapNumber(ebx, ecx, no_reg, alloc_failure); 2356 // Now eax can be overwritten losing one of the arguments as we are 2357 // now done and will not need it any more. 2358 __ mov(eax, ebx); 2359 __ bind(&skip_allocation); 2360 break; 2361 default: UNREACHABLE(); 2362 } 2363 } 2364 2365 2366 void BinaryOpStub::GenerateRegisterArgsPush(MacroAssembler* masm) { 2367 __ pop(ecx); 2368 __ push(edx); 2369 __ push(eax); 2370 __ push(ecx); 2371 } 2372 2373 2374 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { 2375 // TAGGED case: 2376 // Input: 2377 // esp[4]: tagged number input argument (should be number). 2378 // esp[0]: return address. 2379 // Output: 2380 // eax: tagged double result. 2381 // UNTAGGED case: 2382 // Input:: 2383 // esp[0]: return address. 2384 // xmm1: untagged double input argument 2385 // Output: 2386 // xmm1: untagged double result. 2387 2388 Label runtime_call; 2389 Label runtime_call_clear_stack; 2390 Label skip_cache; 2391 const bool tagged = (argument_type_ == TAGGED); 2392 if (tagged) { 2393 // Test that eax is a number. 2394 Label input_not_smi; 2395 Label loaded; 2396 __ mov(eax, Operand(esp, kPointerSize)); 2397 __ JumpIfNotSmi(eax, &input_not_smi, Label::kNear); 2398 // Input is a smi. Untag and load it onto the FPU stack. 2399 // Then load the low and high words of the double into ebx, edx. 2400 STATIC_ASSERT(kSmiTagSize == 1); 2401 __ sar(eax, 1); 2402 __ sub(esp, Immediate(2 * kPointerSize)); 2403 __ mov(Operand(esp, 0), eax); 2404 __ fild_s(Operand(esp, 0)); 2405 __ fst_d(Operand(esp, 0)); 2406 __ pop(edx); 2407 __ pop(ebx); 2408 __ jmp(&loaded, Label::kNear); 2409 __ bind(&input_not_smi); 2410 // Check if input is a HeapNumber. 2411 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 2412 Factory* factory = masm->isolate()->factory(); 2413 __ cmp(ebx, Immediate(factory->heap_number_map())); 2414 __ j(not_equal, &runtime_call); 2415 // Input is a HeapNumber. Push it on the FPU stack and load its 2416 // low and high words into ebx, edx. 2417 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2418 __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset)); 2419 __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset)); 2420 2421 __ bind(&loaded); 2422 } else { // UNTAGGED. 2423 if (CpuFeatures::IsSupported(SSE4_1)) { 2424 CpuFeatures::Scope sse4_scope(SSE4_1); 2425 __ pextrd(edx, xmm1, 0x1); // copy xmm1[63..32] to edx. 2426 } else { 2427 __ pshufd(xmm0, xmm1, 0x1); 2428 __ movd(edx, xmm0); 2429 } 2430 __ movd(ebx, xmm1); 2431 } 2432 2433 // ST[0] or xmm1 == double value 2434 // ebx = low 32 bits of double value 2435 // edx = high 32 bits of double value 2436 // Compute hash (the shifts are arithmetic): 2437 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); 2438 __ mov(ecx, ebx); 2439 __ xor_(ecx, edx); 2440 __ mov(eax, ecx); 2441 __ sar(eax, 16); 2442 __ xor_(ecx, eax); 2443 __ mov(eax, ecx); 2444 __ sar(eax, 8); 2445 __ xor_(ecx, eax); 2446 ASSERT(IsPowerOf2(TranscendentalCache::SubCache::kCacheSize)); 2447 __ and_(ecx, 2448 Immediate(TranscendentalCache::SubCache::kCacheSize - 1)); 2449 2450 // ST[0] or xmm1 == double value. 2451 // ebx = low 32 bits of double value. 2452 // edx = high 32 bits of double value. 2453 // ecx = TranscendentalCache::hash(double value). 2454 ExternalReference cache_array = 2455 ExternalReference::transcendental_cache_array_address(masm->isolate()); 2456 __ mov(eax, Immediate(cache_array)); 2457 int cache_array_index = 2458 type_ * sizeof(masm->isolate()->transcendental_cache()->caches_[0]); 2459 __ mov(eax, Operand(eax, cache_array_index)); 2460 // Eax points to the cache for the type type_. 2461 // If NULL, the cache hasn't been initialized yet, so go through runtime. 2462 __ test(eax, eax); 2463 __ j(zero, &runtime_call_clear_stack); 2464 #ifdef DEBUG 2465 // Check that the layout of cache elements match expectations. 2466 { TranscendentalCache::SubCache::Element test_elem[2]; 2467 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); 2468 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); 2469 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); 2470 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); 2471 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); 2472 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. 2473 CHECK_EQ(0, elem_in0 - elem_start); 2474 CHECK_EQ(kIntSize, elem_in1 - elem_start); 2475 CHECK_EQ(2 * kIntSize, elem_out - elem_start); 2476 } 2477 #endif 2478 // Find the address of the ecx'th entry in the cache, i.e., &eax[ecx*12]. 2479 __ lea(ecx, Operand(ecx, ecx, times_2, 0)); 2480 __ lea(ecx, Operand(eax, ecx, times_4, 0)); 2481 // Check if cache matches: Double value is stored in uint32_t[2] array. 2482 Label cache_miss; 2483 __ cmp(ebx, Operand(ecx, 0)); 2484 __ j(not_equal, &cache_miss, Label::kNear); 2485 __ cmp(edx, Operand(ecx, kIntSize)); 2486 __ j(not_equal, &cache_miss, Label::kNear); 2487 // Cache hit! 2488 Counters* counters = masm->isolate()->counters(); 2489 __ IncrementCounter(counters->transcendental_cache_hit(), 1); 2490 __ mov(eax, Operand(ecx, 2 * kIntSize)); 2491 if (tagged) { 2492 __ fstp(0); 2493 __ ret(kPointerSize); 2494 } else { // UNTAGGED. 2495 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2496 __ Ret(); 2497 } 2498 2499 __ bind(&cache_miss); 2500 __ IncrementCounter(counters->transcendental_cache_miss(), 1); 2501 // Update cache with new value. 2502 // We are short on registers, so use no_reg as scratch. 2503 // This gives slightly larger code. 2504 if (tagged) { 2505 __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack); 2506 } else { // UNTAGGED. 2507 __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); 2508 __ sub(esp, Immediate(kDoubleSize)); 2509 __ movdbl(Operand(esp, 0), xmm1); 2510 __ fld_d(Operand(esp, 0)); 2511 __ add(esp, Immediate(kDoubleSize)); 2512 } 2513 GenerateOperation(masm, type_); 2514 __ mov(Operand(ecx, 0), ebx); 2515 __ mov(Operand(ecx, kIntSize), edx); 2516 __ mov(Operand(ecx, 2 * kIntSize), eax); 2517 __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset)); 2518 if (tagged) { 2519 __ ret(kPointerSize); 2520 } else { // UNTAGGED. 2521 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2522 __ Ret(); 2523 2524 // Skip cache and return answer directly, only in untagged case. 2525 __ bind(&skip_cache); 2526 __ sub(esp, Immediate(kDoubleSize)); 2527 __ movdbl(Operand(esp, 0), xmm1); 2528 __ fld_d(Operand(esp, 0)); 2529 GenerateOperation(masm, type_); 2530 __ fstp_d(Operand(esp, 0)); 2531 __ movdbl(xmm1, Operand(esp, 0)); 2532 __ add(esp, Immediate(kDoubleSize)); 2533 // We return the value in xmm1 without adding it to the cache, but 2534 // we cause a scavenging GC so that future allocations will succeed. 2535 { 2536 FrameScope scope(masm, StackFrame::INTERNAL); 2537 // Allocate an unused object bigger than a HeapNumber. 2538 __ push(Immediate(Smi::FromInt(2 * kDoubleSize))); 2539 __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace); 2540 } 2541 __ Ret(); 2542 } 2543 2544 // Call runtime, doing whatever allocation and cleanup is necessary. 2545 if (tagged) { 2546 __ bind(&runtime_call_clear_stack); 2547 __ fstp(0); 2548 __ bind(&runtime_call); 2549 ExternalReference runtime = 2550 ExternalReference(RuntimeFunction(), masm->isolate()); 2551 __ TailCallExternalReference(runtime, 1, 1); 2552 } else { // UNTAGGED. 2553 __ bind(&runtime_call_clear_stack); 2554 __ bind(&runtime_call); 2555 __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache); 2556 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1); 2557 { 2558 FrameScope scope(masm, StackFrame::INTERNAL); 2559 __ push(eax); 2560 __ CallRuntime(RuntimeFunction(), 1); 2561 } 2562 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2563 __ Ret(); 2564 } 2565 } 2566 2567 2568 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { 2569 switch (type_) { 2570 case TranscendentalCache::SIN: return Runtime::kMath_sin; 2571 case TranscendentalCache::COS: return Runtime::kMath_cos; 2572 case TranscendentalCache::TAN: return Runtime::kMath_tan; 2573 case TranscendentalCache::LOG: return Runtime::kMath_log; 2574 default: 2575 UNIMPLEMENTED(); 2576 return Runtime::kAbort; 2577 } 2578 } 2579 2580 2581 void TranscendentalCacheStub::GenerateOperation( 2582 MacroAssembler* masm, TranscendentalCache::Type type) { 2583 // Only free register is edi. 2584 // Input value is on FP stack, and also in ebx/edx. 2585 // Input value is possibly in xmm1. 2586 // Address of result (a newly allocated HeapNumber) may be in eax. 2587 if (type == TranscendentalCache::SIN || 2588 type == TranscendentalCache::COS || 2589 type == TranscendentalCache::TAN) { 2590 // Both fsin and fcos require arguments in the range +/-2^63 and 2591 // return NaN for infinities and NaN. They can share all code except 2592 // the actual fsin/fcos operation. 2593 Label in_range, done; 2594 // If argument is outside the range -2^63..2^63, fsin/cos doesn't 2595 // work. We must reduce it to the appropriate range. 2596 __ mov(edi, edx); 2597 __ and_(edi, Immediate(0x7ff00000)); // Exponent only. 2598 int supported_exponent_limit = 2599 (63 + HeapNumber::kExponentBias) << HeapNumber::kExponentShift; 2600 __ cmp(edi, Immediate(supported_exponent_limit)); 2601 __ j(below, &in_range, Label::kNear); 2602 // Check for infinity and NaN. Both return NaN for sin. 2603 __ cmp(edi, Immediate(0x7ff00000)); 2604 Label non_nan_result; 2605 __ j(not_equal, &non_nan_result, Label::kNear); 2606 // Input is +/-Infinity or NaN. Result is NaN. 2607 __ fstp(0); 2608 // NaN is represented by 0x7ff8000000000000. 2609 __ push(Immediate(0x7ff80000)); 2610 __ push(Immediate(0)); 2611 __ fld_d(Operand(esp, 0)); 2612 __ add(esp, Immediate(2 * kPointerSize)); 2613 __ jmp(&done, Label::kNear); 2614 2615 __ bind(&non_nan_result); 2616 2617 // Use fpmod to restrict argument to the range +/-2*PI. 2618 __ mov(edi, eax); // Save eax before using fnstsw_ax. 2619 __ fldpi(); 2620 __ fadd(0); 2621 __ fld(1); 2622 // FPU Stack: input, 2*pi, input. 2623 { 2624 Label no_exceptions; 2625 __ fwait(); 2626 __ fnstsw_ax(); 2627 // Clear if Illegal Operand or Zero Division exceptions are set. 2628 __ test(eax, Immediate(5)); 2629 __ j(zero, &no_exceptions, Label::kNear); 2630 __ fnclex(); 2631 __ bind(&no_exceptions); 2632 } 2633 2634 // Compute st(0) % st(1) 2635 { 2636 Label partial_remainder_loop; 2637 __ bind(&partial_remainder_loop); 2638 __ fprem1(); 2639 __ fwait(); 2640 __ fnstsw_ax(); 2641 __ test(eax, Immediate(0x400 /* C2 */)); 2642 // If C2 is set, computation only has partial result. Loop to 2643 // continue computation. 2644 __ j(not_zero, &partial_remainder_loop); 2645 } 2646 // FPU Stack: input, 2*pi, input % 2*pi 2647 __ fstp(2); 2648 __ fstp(0); 2649 __ mov(eax, edi); // Restore eax (allocated HeapNumber pointer). 2650 2651 // FPU Stack: input % 2*pi 2652 __ bind(&in_range); 2653 switch (type) { 2654 case TranscendentalCache::SIN: 2655 __ fsin(); 2656 break; 2657 case TranscendentalCache::COS: 2658 __ fcos(); 2659 break; 2660 case TranscendentalCache::TAN: 2661 // FPTAN calculates tangent onto st(0) and pushes 1.0 onto the 2662 // FP register stack. 2663 __ fptan(); 2664 __ fstp(0); // Pop FP register stack. 2665 break; 2666 default: 2667 UNREACHABLE(); 2668 } 2669 __ bind(&done); 2670 } else { 2671 ASSERT(type == TranscendentalCache::LOG); 2672 __ fldln2(); 2673 __ fxch(); 2674 __ fyl2x(); 2675 } 2676 } 2677 2678 2679 // Input: edx, eax are the left and right objects of a bit op. 2680 // Output: eax, ecx are left and right integers for a bit op. 2681 void FloatingPointHelper::LoadUnknownsAsIntegers(MacroAssembler* masm, 2682 bool use_sse3, 2683 Label* conversion_failure) { 2684 // Check float operands. 2685 Label arg1_is_object, check_undefined_arg1; 2686 Label arg2_is_object, check_undefined_arg2; 2687 Label load_arg2, done; 2688 2689 // Test if arg1 is a Smi. 2690 __ JumpIfNotSmi(edx, &arg1_is_object, Label::kNear); 2691 2692 __ SmiUntag(edx); 2693 __ jmp(&load_arg2); 2694 2695 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 2696 __ bind(&check_undefined_arg1); 2697 Factory* factory = masm->isolate()->factory(); 2698 __ cmp(edx, factory->undefined_value()); 2699 __ j(not_equal, conversion_failure); 2700 __ mov(edx, Immediate(0)); 2701 __ jmp(&load_arg2); 2702 2703 __ bind(&arg1_is_object); 2704 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 2705 __ cmp(ebx, factory->heap_number_map()); 2706 __ j(not_equal, &check_undefined_arg1); 2707 2708 // Get the untagged integer version of the edx heap number in ecx. 2709 IntegerConvert(masm, edx, use_sse3, conversion_failure); 2710 __ mov(edx, ecx); 2711 2712 // Here edx has the untagged integer, eax has a Smi or a heap number. 2713 __ bind(&load_arg2); 2714 2715 // Test if arg2 is a Smi. 2716 __ JumpIfNotSmi(eax, &arg2_is_object, Label::kNear); 2717 2718 __ SmiUntag(eax); 2719 __ mov(ecx, eax); 2720 __ jmp(&done); 2721 2722 // If the argument is undefined it converts to zero (ECMA-262, section 9.5). 2723 __ bind(&check_undefined_arg2); 2724 __ cmp(eax, factory->undefined_value()); 2725 __ j(not_equal, conversion_failure); 2726 __ mov(ecx, Immediate(0)); 2727 __ jmp(&done); 2728 2729 __ bind(&arg2_is_object); 2730 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 2731 __ cmp(ebx, factory->heap_number_map()); 2732 __ j(not_equal, &check_undefined_arg2); 2733 2734 // Get the untagged integer version of the eax heap number in ecx. 2735 IntegerConvert(masm, eax, use_sse3, conversion_failure); 2736 __ bind(&done); 2737 __ mov(eax, edx); 2738 } 2739 2740 2741 void FloatingPointHelper::CheckLoadedIntegersWereInt32(MacroAssembler* masm, 2742 bool use_sse3, 2743 Label* not_int32) { 2744 return; 2745 } 2746 2747 2748 void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm, 2749 Register number) { 2750 Label load_smi, done; 2751 2752 __ JumpIfSmi(number, &load_smi, Label::kNear); 2753 __ fld_d(FieldOperand(number, HeapNumber::kValueOffset)); 2754 __ jmp(&done, Label::kNear); 2755 2756 __ bind(&load_smi); 2757 __ SmiUntag(number); 2758 __ push(number); 2759 __ fild_s(Operand(esp, 0)); 2760 __ pop(number); 2761 2762 __ bind(&done); 2763 } 2764 2765 2766 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm) { 2767 Label load_smi_edx, load_eax, load_smi_eax, done; 2768 // Load operand in edx into xmm0. 2769 __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); 2770 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 2771 2772 __ bind(&load_eax); 2773 // Load operand in eax into xmm1. 2774 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); 2775 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2776 __ jmp(&done, Label::kNear); 2777 2778 __ bind(&load_smi_edx); 2779 __ SmiUntag(edx); // Untag smi before converting to float. 2780 __ cvtsi2sd(xmm0, edx); 2781 __ SmiTag(edx); // Retag smi for heap number overwriting test. 2782 __ jmp(&load_eax); 2783 2784 __ bind(&load_smi_eax); 2785 __ SmiUntag(eax); // Untag smi before converting to float. 2786 __ cvtsi2sd(xmm1, eax); 2787 __ SmiTag(eax); // Retag smi for heap number overwriting test. 2788 2789 __ bind(&done); 2790 } 2791 2792 2793 void FloatingPointHelper::LoadSSE2Operands(MacroAssembler* masm, 2794 Label* not_numbers) { 2795 Label load_smi_edx, load_eax, load_smi_eax, load_float_eax, done; 2796 // Load operand in edx into xmm0, or branch to not_numbers. 2797 __ JumpIfSmi(edx, &load_smi_edx, Label::kNear); 2798 Factory* factory = masm->isolate()->factory(); 2799 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), factory->heap_number_map()); 2800 __ j(not_equal, not_numbers); // Argument in edx is not a number. 2801 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 2802 __ bind(&load_eax); 2803 // Load operand in eax into xmm1, or branch to not_numbers. 2804 __ JumpIfSmi(eax, &load_smi_eax, Label::kNear); 2805 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), factory->heap_number_map()); 2806 __ j(equal, &load_float_eax, Label::kNear); 2807 __ jmp(not_numbers); // Argument in eax is not a number. 2808 __ bind(&load_smi_edx); 2809 __ SmiUntag(edx); // Untag smi before converting to float. 2810 __ cvtsi2sd(xmm0, edx); 2811 __ SmiTag(edx); // Retag smi for heap number overwriting test. 2812 __ jmp(&load_eax); 2813 __ bind(&load_smi_eax); 2814 __ SmiUntag(eax); // Untag smi before converting to float. 2815 __ cvtsi2sd(xmm1, eax); 2816 __ SmiTag(eax); // Retag smi for heap number overwriting test. 2817 __ jmp(&done, Label::kNear); 2818 __ bind(&load_float_eax); 2819 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 2820 __ bind(&done); 2821 } 2822 2823 2824 void FloatingPointHelper::LoadSSE2Smis(MacroAssembler* masm, 2825 Register scratch) { 2826 const Register left = edx; 2827 const Register right = eax; 2828 __ mov(scratch, left); 2829 ASSERT(!scratch.is(right)); // We're about to clobber scratch. 2830 __ SmiUntag(scratch); 2831 __ cvtsi2sd(xmm0, scratch); 2832 2833 __ mov(scratch, right); 2834 __ SmiUntag(scratch); 2835 __ cvtsi2sd(xmm1, scratch); 2836 } 2837 2838 2839 void FloatingPointHelper::CheckSSE2OperandsAreInt32(MacroAssembler* masm, 2840 Label* non_int32, 2841 Register scratch) { 2842 __ cvttsd2si(scratch, Operand(xmm0)); 2843 __ cvtsi2sd(xmm2, scratch); 2844 __ ucomisd(xmm0, xmm2); 2845 __ j(not_zero, non_int32); 2846 __ j(carry, non_int32); 2847 __ cvttsd2si(scratch, Operand(xmm1)); 2848 __ cvtsi2sd(xmm2, scratch); 2849 __ ucomisd(xmm1, xmm2); 2850 __ j(not_zero, non_int32); 2851 __ j(carry, non_int32); 2852 } 2853 2854 2855 void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm, 2856 Register scratch, 2857 ArgLocation arg_location) { 2858 Label load_smi_1, load_smi_2, done_load_1, done; 2859 if (arg_location == ARGS_IN_REGISTERS) { 2860 __ mov(scratch, edx); 2861 } else { 2862 __ mov(scratch, Operand(esp, 2 * kPointerSize)); 2863 } 2864 __ JumpIfSmi(scratch, &load_smi_1, Label::kNear); 2865 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); 2866 __ bind(&done_load_1); 2867 2868 if (arg_location == ARGS_IN_REGISTERS) { 2869 __ mov(scratch, eax); 2870 } else { 2871 __ mov(scratch, Operand(esp, 1 * kPointerSize)); 2872 } 2873 __ JumpIfSmi(scratch, &load_smi_2, Label::kNear); 2874 __ fld_d(FieldOperand(scratch, HeapNumber::kValueOffset)); 2875 __ jmp(&done, Label::kNear); 2876 2877 __ bind(&load_smi_1); 2878 __ SmiUntag(scratch); 2879 __ push(scratch); 2880 __ fild_s(Operand(esp, 0)); 2881 __ pop(scratch); 2882 __ jmp(&done_load_1); 2883 2884 __ bind(&load_smi_2); 2885 __ SmiUntag(scratch); 2886 __ push(scratch); 2887 __ fild_s(Operand(esp, 0)); 2888 __ pop(scratch); 2889 2890 __ bind(&done); 2891 } 2892 2893 2894 void FloatingPointHelper::LoadFloatSmis(MacroAssembler* masm, 2895 Register scratch) { 2896 const Register left = edx; 2897 const Register right = eax; 2898 __ mov(scratch, left); 2899 ASSERT(!scratch.is(right)); // We're about to clobber scratch. 2900 __ SmiUntag(scratch); 2901 __ push(scratch); 2902 __ fild_s(Operand(esp, 0)); 2903 2904 __ mov(scratch, right); 2905 __ SmiUntag(scratch); 2906 __ mov(Operand(esp, 0), scratch); 2907 __ fild_s(Operand(esp, 0)); 2908 __ pop(scratch); 2909 } 2910 2911 2912 void FloatingPointHelper::CheckFloatOperands(MacroAssembler* masm, 2913 Label* non_float, 2914 Register scratch) { 2915 Label test_other, done; 2916 // Test if both operands are floats or smi -> scratch=k_is_float; 2917 // Otherwise scratch = k_not_float. 2918 __ JumpIfSmi(edx, &test_other, Label::kNear); 2919 __ mov(scratch, FieldOperand(edx, HeapObject::kMapOffset)); 2920 Factory* factory = masm->isolate()->factory(); 2921 __ cmp(scratch, factory->heap_number_map()); 2922 __ j(not_equal, non_float); // argument in edx is not a number -> NaN 2923 2924 __ bind(&test_other); 2925 __ JumpIfSmi(eax, &done, Label::kNear); 2926 __ mov(scratch, FieldOperand(eax, HeapObject::kMapOffset)); 2927 __ cmp(scratch, factory->heap_number_map()); 2928 __ j(not_equal, non_float); // argument in eax is not a number -> NaN 2929 2930 // Fall-through: Both operands are numbers. 2931 __ bind(&done); 2932 } 2933 2934 2935 void FloatingPointHelper::CheckFloatOperandsAreInt32(MacroAssembler* masm, 2936 Label* non_int32) { 2937 return; 2938 } 2939 2940 2941 void MathPowStub::Generate(MacroAssembler* masm) { 2942 CpuFeatures::Scope use_sse2(SSE2); 2943 Factory* factory = masm->isolate()->factory(); 2944 const Register exponent = eax; 2945 const Register base = edx; 2946 const Register scratch = ecx; 2947 const XMMRegister double_result = xmm3; 2948 const XMMRegister double_base = xmm2; 2949 const XMMRegister double_exponent = xmm1; 2950 const XMMRegister double_scratch = xmm4; 2951 2952 Label call_runtime, done, exponent_not_smi, int_exponent; 2953 2954 // Save 1 in double_result - we need this several times later on. 2955 __ mov(scratch, Immediate(1)); 2956 __ cvtsi2sd(double_result, scratch); 2957 2958 if (exponent_type_ == ON_STACK) { 2959 Label base_is_smi, unpack_exponent; 2960 // The exponent and base are supplied as arguments on the stack. 2961 // This can only happen if the stub is called from non-optimized code. 2962 // Load input parameters from stack. 2963 __ mov(base, Operand(esp, 2 * kPointerSize)); 2964 __ mov(exponent, Operand(esp, 1 * kPointerSize)); 2965 2966 __ JumpIfSmi(base, &base_is_smi, Label::kNear); 2967 __ cmp(FieldOperand(base, HeapObject::kMapOffset), 2968 factory->heap_number_map()); 2969 __ j(not_equal, &call_runtime); 2970 2971 __ movdbl(double_base, FieldOperand(base, HeapNumber::kValueOffset)); 2972 __ jmp(&unpack_exponent, Label::kNear); 2973 2974 __ bind(&base_is_smi); 2975 __ SmiUntag(base); 2976 __ cvtsi2sd(double_base, base); 2977 2978 __ bind(&unpack_exponent); 2979 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); 2980 __ SmiUntag(exponent); 2981 __ jmp(&int_exponent); 2982 2983 __ bind(&exponent_not_smi); 2984 __ cmp(FieldOperand(exponent, HeapObject::kMapOffset), 2985 factory->heap_number_map()); 2986 __ j(not_equal, &call_runtime); 2987 __ movdbl(double_exponent, 2988 FieldOperand(exponent, HeapNumber::kValueOffset)); 2989 } else if (exponent_type_ == TAGGED) { 2990 __ JumpIfNotSmi(exponent, &exponent_not_smi, Label::kNear); 2991 __ SmiUntag(exponent); 2992 __ jmp(&int_exponent); 2993 2994 __ bind(&exponent_not_smi); 2995 __ movdbl(double_exponent, 2996 FieldOperand(exponent, HeapNumber::kValueOffset)); 2997 } 2998 2999 if (exponent_type_ != INTEGER) { 3000 Label fast_power; 3001 // Detect integer exponents stored as double. 3002 __ cvttsd2si(exponent, Operand(double_exponent)); 3003 // Skip to runtime if possibly NaN (indicated by the indefinite integer). 3004 __ cmp(exponent, Immediate(0x80000000u)); 3005 __ j(equal, &call_runtime); 3006 __ cvtsi2sd(double_scratch, exponent); 3007 // Already ruled out NaNs for exponent. 3008 __ ucomisd(double_exponent, double_scratch); 3009 __ j(equal, &int_exponent); 3010 3011 if (exponent_type_ == ON_STACK) { 3012 // Detect square root case. Crankshaft detects constant +/-0.5 at 3013 // compile time and uses DoMathPowHalf instead. We then skip this check 3014 // for non-constant cases of +/-0.5 as these hardly occur. 3015 Label continue_sqrt, continue_rsqrt, not_plus_half; 3016 // Test for 0.5. 3017 // Load double_scratch with 0.5. 3018 __ mov(scratch, Immediate(0x3F000000u)); 3019 __ movd(double_scratch, scratch); 3020 __ cvtss2sd(double_scratch, double_scratch); 3021 // Already ruled out NaNs for exponent. 3022 __ ucomisd(double_scratch, double_exponent); 3023 __ j(not_equal, ¬_plus_half, Label::kNear); 3024 3025 // Calculates square root of base. Check for the special case of 3026 // Math.pow(-Infinity, 0.5) == Infinity (ECMA spec, 15.8.2.13). 3027 // According to IEEE-754, single-precision -Infinity has the highest 3028 // 9 bits set and the lowest 23 bits cleared. 3029 __ mov(scratch, 0xFF800000u); 3030 __ movd(double_scratch, scratch); 3031 __ cvtss2sd(double_scratch, double_scratch); 3032 __ ucomisd(double_base, double_scratch); 3033 // Comparing -Infinity with NaN results in "unordered", which sets the 3034 // zero flag as if both were equal. However, it also sets the carry flag. 3035 __ j(not_equal, &continue_sqrt, Label::kNear); 3036 __ j(carry, &continue_sqrt, Label::kNear); 3037 3038 // Set result to Infinity in the special case. 3039 __ xorps(double_result, double_result); 3040 __ subsd(double_result, double_scratch); 3041 __ jmp(&done); 3042 3043 __ bind(&continue_sqrt); 3044 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 3045 __ xorps(double_scratch, double_scratch); 3046 __ addsd(double_scratch, double_base); // Convert -0 to +0. 3047 __ sqrtsd(double_result, double_scratch); 3048 __ jmp(&done); 3049 3050 // Test for -0.5. 3051 __ bind(¬_plus_half); 3052 // Load double_exponent with -0.5 by substracting 1. 3053 __ subsd(double_scratch, double_result); 3054 // Already ruled out NaNs for exponent. 3055 __ ucomisd(double_scratch, double_exponent); 3056 __ j(not_equal, &fast_power, Label::kNear); 3057 3058 // Calculates reciprocal of square root of base. Check for the special 3059 // case of Math.pow(-Infinity, -0.5) == 0 (ECMA spec, 15.8.2.13). 3060 // According to IEEE-754, single-precision -Infinity has the highest 3061 // 9 bits set and the lowest 23 bits cleared. 3062 __ mov(scratch, 0xFF800000u); 3063 __ movd(double_scratch, scratch); 3064 __ cvtss2sd(double_scratch, double_scratch); 3065 __ ucomisd(double_base, double_scratch); 3066 // Comparing -Infinity with NaN results in "unordered", which sets the 3067 // zero flag as if both were equal. However, it also sets the carry flag. 3068 __ j(not_equal, &continue_rsqrt, Label::kNear); 3069 __ j(carry, &continue_rsqrt, Label::kNear); 3070 3071 // Set result to 0 in the special case. 3072 __ xorps(double_result, double_result); 3073 __ jmp(&done); 3074 3075 __ bind(&continue_rsqrt); 3076 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. 3077 __ xorps(double_exponent, double_exponent); 3078 __ addsd(double_exponent, double_base); // Convert -0 to +0. 3079 __ sqrtsd(double_exponent, double_exponent); 3080 __ divsd(double_result, double_exponent); 3081 __ jmp(&done); 3082 } 3083 3084 // Using FPU instructions to calculate power. 3085 Label fast_power_failed; 3086 __ bind(&fast_power); 3087 __ fnclex(); // Clear flags to catch exceptions later. 3088 // Transfer (B)ase and (E)xponent onto the FPU register stack. 3089 __ sub(esp, Immediate(kDoubleSize)); 3090 __ movdbl(Operand(esp, 0), double_exponent); 3091 __ fld_d(Operand(esp, 0)); // E 3092 __ movdbl(Operand(esp, 0), double_base); 3093 __ fld_d(Operand(esp, 0)); // B, E 3094 3095 // Exponent is in st(1) and base is in st(0) 3096 // B ^ E = (2^(E * log2(B)) - 1) + 1 = (2^X - 1) + 1 for X = E * log2(B) 3097 // FYL2X calculates st(1) * log2(st(0)) 3098 __ fyl2x(); // X 3099 __ fld(0); // X, X 3100 __ frndint(); // rnd(X), X 3101 __ fsub(1); // rnd(X), X-rnd(X) 3102 __ fxch(1); // X - rnd(X), rnd(X) 3103 // F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1 3104 __ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X) 3105 __ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X) 3106 __ faddp(1); // 1, 2^(X-rnd(X)), rnd(X) 3107 // FSCALE calculates st(0) * 2^st(1) 3108 __ fscale(); // 2^X, rnd(X) 3109 __ fstp(1); 3110 // Bail out to runtime in case of exceptions in the status word. 3111 __ fnstsw_ax(); 3112 __ test_b(eax, 0x5F); // We check for all but precision exception. 3113 __ j(not_zero, &fast_power_failed, Label::kNear); 3114 __ fstp_d(Operand(esp, 0)); 3115 __ movdbl(double_result, Operand(esp, 0)); 3116 __ add(esp, Immediate(kDoubleSize)); 3117 __ jmp(&done); 3118 3119 __ bind(&fast_power_failed); 3120 __ fninit(); 3121 __ add(esp, Immediate(kDoubleSize)); 3122 __ jmp(&call_runtime); 3123 } 3124 3125 // Calculate power with integer exponent. 3126 __ bind(&int_exponent); 3127 const XMMRegister double_scratch2 = double_exponent; 3128 __ mov(scratch, exponent); // Back up exponent. 3129 __ movsd(double_scratch, double_base); // Back up base. 3130 __ movsd(double_scratch2, double_result); // Load double_exponent with 1. 3131 3132 // Get absolute value of exponent. 3133 Label no_neg, while_true, no_multiply; 3134 __ test(scratch, scratch); 3135 __ j(positive, &no_neg, Label::kNear); 3136 __ neg(scratch); 3137 __ bind(&no_neg); 3138 3139 __ bind(&while_true); 3140 __ shr(scratch, 1); 3141 __ j(not_carry, &no_multiply, Label::kNear); 3142 __ mulsd(double_result, double_scratch); 3143 __ bind(&no_multiply); 3144 3145 __ mulsd(double_scratch, double_scratch); 3146 __ j(not_zero, &while_true); 3147 3148 // scratch has the original value of the exponent - if the exponent is 3149 // negative, return 1/result. 3150 __ test(exponent, exponent); 3151 __ j(positive, &done); 3152 __ divsd(double_scratch2, double_result); 3153 __ movsd(double_result, double_scratch2); 3154 // Test whether result is zero. Bail out to check for subnormal result. 3155 // Due to subnormals, x^-y == (1/x)^y does not hold in all cases. 3156 __ xorps(double_scratch2, double_scratch2); 3157 __ ucomisd(double_scratch2, double_result); // Result cannot be NaN. 3158 // double_exponent aliased as double_scratch2 has already been overwritten 3159 // and may not have contained the exponent value in the first place when the 3160 // exponent is a smi. We reset it with exponent value before bailing out. 3161 __ j(not_equal, &done); 3162 __ cvtsi2sd(double_exponent, exponent); 3163 3164 // Returning or bailing out. 3165 Counters* counters = masm->isolate()->counters(); 3166 if (exponent_type_ == ON_STACK) { 3167 // The arguments are still on the stack. 3168 __ bind(&call_runtime); 3169 __ TailCallRuntime(Runtime::kMath_pow_cfunction, 2, 1); 3170 3171 // The stub is called from non-optimized code, which expects the result 3172 // as heap number in exponent. 3173 __ bind(&done); 3174 __ AllocateHeapNumber(eax, scratch, base, &call_runtime); 3175 __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), double_result); 3176 __ IncrementCounter(counters->math_pow(), 1); 3177 __ ret(2 * kPointerSize); 3178 } else { 3179 __ bind(&call_runtime); 3180 { 3181 AllowExternalCallThatCantCauseGC scope(masm); 3182 __ PrepareCallCFunction(4, scratch); 3183 __ movdbl(Operand(esp, 0 * kDoubleSize), double_base); 3184 __ movdbl(Operand(esp, 1 * kDoubleSize), double_exponent); 3185 __ CallCFunction( 3186 ExternalReference::power_double_double_function(masm->isolate()), 4); 3187 } 3188 // Return value is in st(0) on ia32. 3189 // Store it into the (fixed) result register. 3190 __ sub(esp, Immediate(kDoubleSize)); 3191 __ fstp_d(Operand(esp, 0)); 3192 __ movdbl(double_result, Operand(esp, 0)); 3193 __ add(esp, Immediate(kDoubleSize)); 3194 3195 __ bind(&done); 3196 __ IncrementCounter(counters->math_pow(), 1); 3197 __ ret(0); 3198 } 3199 } 3200 3201 3202 void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) { 3203 // The key is in edx and the parameter count is in eax. 3204 3205 // The displacement is used for skipping the frame pointer on the 3206 // stack. It is the offset of the last parameter (if any) relative 3207 // to the frame pointer. 3208 static const int kDisplacement = 1 * kPointerSize; 3209 3210 // Check that the key is a smi. 3211 Label slow; 3212 __ JumpIfNotSmi(edx, &slow, Label::kNear); 3213 3214 // Check if the calling frame is an arguments adaptor frame. 3215 Label adaptor; 3216 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 3217 __ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset)); 3218 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 3219 __ j(equal, &adaptor, Label::kNear); 3220 3221 // Check index against formal parameters count limit passed in 3222 // through register eax. Use unsigned comparison to get negative 3223 // check for free. 3224 __ cmp(edx, eax); 3225 __ j(above_equal, &slow, Label::kNear); 3226 3227 // Read the argument from the stack and return it. 3228 STATIC_ASSERT(kSmiTagSize == 1); 3229 STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. 3230 __ lea(ebx, Operand(ebp, eax, times_2, 0)); 3231 __ neg(edx); 3232 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); 3233 __ ret(0); 3234 3235 // Arguments adaptor case: Check index against actual arguments 3236 // limit found in the arguments adaptor frame. Use unsigned 3237 // comparison to get negative check for free. 3238 __ bind(&adaptor); 3239 __ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 3240 __ cmp(edx, ecx); 3241 __ j(above_equal, &slow, Label::kNear); 3242 3243 // Read the argument from the stack and return it. 3244 STATIC_ASSERT(kSmiTagSize == 1); 3245 STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these. 3246 __ lea(ebx, Operand(ebx, ecx, times_2, 0)); 3247 __ neg(edx); 3248 __ mov(eax, Operand(ebx, edx, times_2, kDisplacement)); 3249 __ ret(0); 3250 3251 // Slow-case: Handle non-smi or out-of-bounds access to arguments 3252 // by calling the runtime system. 3253 __ bind(&slow); 3254 __ pop(ebx); // Return address. 3255 __ push(edx); 3256 __ push(ebx); 3257 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); 3258 } 3259 3260 3261 void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { 3262 // esp[0] : return address 3263 // esp[4] : number of parameters 3264 // esp[8] : receiver displacement 3265 // esp[12] : function 3266 3267 // Check if the calling frame is an arguments adaptor frame. 3268 Label runtime; 3269 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 3270 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 3271 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 3272 __ j(not_equal, &runtime, Label::kNear); 3273 3274 // Patch the arguments.length and the parameters pointer. 3275 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 3276 __ mov(Operand(esp, 1 * kPointerSize), ecx); 3277 __ lea(edx, Operand(edx, ecx, times_2, 3278 StandardFrameConstants::kCallerSPOffset)); 3279 __ mov(Operand(esp, 2 * kPointerSize), edx); 3280 3281 __ bind(&runtime); 3282 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); 3283 } 3284 3285 3286 void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { 3287 // esp[0] : return address 3288 // esp[4] : number of parameters (tagged) 3289 // esp[8] : receiver displacement 3290 // esp[12] : function 3291 3292 // ebx = parameter count (tagged) 3293 __ mov(ebx, Operand(esp, 1 * kPointerSize)); 3294 3295 // Check if the calling frame is an arguments adaptor frame. 3296 // TODO(rossberg): Factor out some of the bits that are shared with the other 3297 // Generate* functions. 3298 Label runtime; 3299 Label adaptor_frame, try_allocate; 3300 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 3301 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 3302 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 3303 __ j(equal, &adaptor_frame, Label::kNear); 3304 3305 // No adaptor, parameter count = argument count. 3306 __ mov(ecx, ebx); 3307 __ jmp(&try_allocate, Label::kNear); 3308 3309 // We have an adaptor frame. Patch the parameters pointer. 3310 __ bind(&adaptor_frame); 3311 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 3312 __ lea(edx, Operand(edx, ecx, times_2, 3313 StandardFrameConstants::kCallerSPOffset)); 3314 __ mov(Operand(esp, 2 * kPointerSize), edx); 3315 3316 // ebx = parameter count (tagged) 3317 // ecx = argument count (tagged) 3318 // esp[4] = parameter count (tagged) 3319 // esp[8] = address of receiver argument 3320 // Compute the mapped parameter count = min(ebx, ecx) in ebx. 3321 __ cmp(ebx, ecx); 3322 __ j(less_equal, &try_allocate, Label::kNear); 3323 __ mov(ebx, ecx); 3324 3325 __ bind(&try_allocate); 3326 3327 // Save mapped parameter count. 3328 __ push(ebx); 3329 3330 // Compute the sizes of backing store, parameter map, and arguments object. 3331 // 1. Parameter map, has 2 extra words containing context and backing store. 3332 const int kParameterMapHeaderSize = 3333 FixedArray::kHeaderSize + 2 * kPointerSize; 3334 Label no_parameter_map; 3335 __ test(ebx, ebx); 3336 __ j(zero, &no_parameter_map, Label::kNear); 3337 __ lea(ebx, Operand(ebx, times_2, kParameterMapHeaderSize)); 3338 __ bind(&no_parameter_map); 3339 3340 // 2. Backing store. 3341 __ lea(ebx, Operand(ebx, ecx, times_2, FixedArray::kHeaderSize)); 3342 3343 // 3. Arguments object. 3344 __ add(ebx, Immediate(Heap::kArgumentsObjectSize)); 3345 3346 // Do the allocation of all three objects in one go. 3347 __ AllocateInNewSpace(ebx, eax, edx, edi, &runtime, TAG_OBJECT); 3348 3349 // eax = address of new object(s) (tagged) 3350 // ecx = argument count (tagged) 3351 // esp[0] = mapped parameter count (tagged) 3352 // esp[8] = parameter count (tagged) 3353 // esp[12] = address of receiver argument 3354 // Get the arguments boilerplate from the current (global) context into edi. 3355 Label has_mapped_parameters, copy; 3356 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 3357 __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); 3358 __ mov(ebx, Operand(esp, 0 * kPointerSize)); 3359 __ test(ebx, ebx); 3360 __ j(not_zero, &has_mapped_parameters, Label::kNear); 3361 __ mov(edi, Operand(edi, 3362 Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX))); 3363 __ jmp(©, Label::kNear); 3364 3365 __ bind(&has_mapped_parameters); 3366 __ mov(edi, Operand(edi, 3367 Context::SlotOffset(Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX))); 3368 __ bind(©); 3369 3370 // eax = address of new object (tagged) 3371 // ebx = mapped parameter count (tagged) 3372 // ecx = argument count (tagged) 3373 // edi = address of boilerplate object (tagged) 3374 // esp[0] = mapped parameter count (tagged) 3375 // esp[8] = parameter count (tagged) 3376 // esp[12] = address of receiver argument 3377 // Copy the JS object part. 3378 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 3379 __ mov(edx, FieldOperand(edi, i)); 3380 __ mov(FieldOperand(eax, i), edx); 3381 } 3382 3383 // Set up the callee in-object property. 3384 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); 3385 __ mov(edx, Operand(esp, 4 * kPointerSize)); 3386 __ mov(FieldOperand(eax, JSObject::kHeaderSize + 3387 Heap::kArgumentsCalleeIndex * kPointerSize), 3388 edx); 3389 3390 // Use the length (smi tagged) and set that as an in-object property too. 3391 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 3392 __ mov(FieldOperand(eax, JSObject::kHeaderSize + 3393 Heap::kArgumentsLengthIndex * kPointerSize), 3394 ecx); 3395 3396 // Set up the elements pointer in the allocated arguments object. 3397 // If we allocated a parameter map, edi will point there, otherwise to the 3398 // backing store. 3399 __ lea(edi, Operand(eax, Heap::kArgumentsObjectSize)); 3400 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); 3401 3402 // eax = address of new object (tagged) 3403 // ebx = mapped parameter count (tagged) 3404 // ecx = argument count (tagged) 3405 // edi = address of parameter map or backing store (tagged) 3406 // esp[0] = mapped parameter count (tagged) 3407 // esp[8] = parameter count (tagged) 3408 // esp[12] = address of receiver argument 3409 // Free a register. 3410 __ push(eax); 3411 3412 // Initialize parameter map. If there are no mapped arguments, we're done. 3413 Label skip_parameter_map; 3414 __ test(ebx, ebx); 3415 __ j(zero, &skip_parameter_map); 3416 3417 __ mov(FieldOperand(edi, FixedArray::kMapOffset), 3418 Immediate(FACTORY->non_strict_arguments_elements_map())); 3419 __ lea(eax, Operand(ebx, reinterpret_cast<intptr_t>(Smi::FromInt(2)))); 3420 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), eax); 3421 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 0 * kPointerSize), esi); 3422 __ lea(eax, Operand(edi, ebx, times_2, kParameterMapHeaderSize)); 3423 __ mov(FieldOperand(edi, FixedArray::kHeaderSize + 1 * kPointerSize), eax); 3424 3425 // Copy the parameter slots and the holes in the arguments. 3426 // We need to fill in mapped_parameter_count slots. They index the context, 3427 // where parameters are stored in reverse order, at 3428 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 3429 // The mapped parameter thus need to get indices 3430 // MIN_CONTEXT_SLOTS+parameter_count-1 .. 3431 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count 3432 // We loop from right to left. 3433 Label parameters_loop, parameters_test; 3434 __ push(ecx); 3435 __ mov(eax, Operand(esp, 2 * kPointerSize)); 3436 __ mov(ebx, Immediate(Smi::FromInt(Context::MIN_CONTEXT_SLOTS))); 3437 __ add(ebx, Operand(esp, 4 * kPointerSize)); 3438 __ sub(ebx, eax); 3439 __ mov(ecx, FACTORY->the_hole_value()); 3440 __ mov(edx, edi); 3441 __ lea(edi, Operand(edi, eax, times_2, kParameterMapHeaderSize)); 3442 // eax = loop variable (tagged) 3443 // ebx = mapping index (tagged) 3444 // ecx = the hole value 3445 // edx = address of parameter map (tagged) 3446 // edi = address of backing store (tagged) 3447 // esp[0] = argument count (tagged) 3448 // esp[4] = address of new object (tagged) 3449 // esp[8] = mapped parameter count (tagged) 3450 // esp[16] = parameter count (tagged) 3451 // esp[20] = address of receiver argument 3452 __ jmp(¶meters_test, Label::kNear); 3453 3454 __ bind(¶meters_loop); 3455 __ sub(eax, Immediate(Smi::FromInt(1))); 3456 __ mov(FieldOperand(edx, eax, times_2, kParameterMapHeaderSize), ebx); 3457 __ mov(FieldOperand(edi, eax, times_2, FixedArray::kHeaderSize), ecx); 3458 __ add(ebx, Immediate(Smi::FromInt(1))); 3459 __ bind(¶meters_test); 3460 __ test(eax, eax); 3461 __ j(not_zero, ¶meters_loop, Label::kNear); 3462 __ pop(ecx); 3463 3464 __ bind(&skip_parameter_map); 3465 3466 // ecx = argument count (tagged) 3467 // edi = address of backing store (tagged) 3468 // esp[0] = address of new object (tagged) 3469 // esp[4] = mapped parameter count (tagged) 3470 // esp[12] = parameter count (tagged) 3471 // esp[16] = address of receiver argument 3472 // Copy arguments header and remaining slots (if there are any). 3473 __ mov(FieldOperand(edi, FixedArray::kMapOffset), 3474 Immediate(FACTORY->fixed_array_map())); 3475 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); 3476 3477 Label arguments_loop, arguments_test; 3478 __ mov(ebx, Operand(esp, 1 * kPointerSize)); 3479 __ mov(edx, Operand(esp, 4 * kPointerSize)); 3480 __ sub(edx, ebx); // Is there a smarter way to do negative scaling? 3481 __ sub(edx, ebx); 3482 __ jmp(&arguments_test, Label::kNear); 3483 3484 __ bind(&arguments_loop); 3485 __ sub(edx, Immediate(kPointerSize)); 3486 __ mov(eax, Operand(edx, 0)); 3487 __ mov(FieldOperand(edi, ebx, times_2, FixedArray::kHeaderSize), eax); 3488 __ add(ebx, Immediate(Smi::FromInt(1))); 3489 3490 __ bind(&arguments_test); 3491 __ cmp(ebx, ecx); 3492 __ j(less, &arguments_loop, Label::kNear); 3493 3494 // Restore. 3495 __ pop(eax); // Address of arguments object. 3496 __ pop(ebx); // Parameter count. 3497 3498 // Return and remove the on-stack parameters. 3499 __ ret(3 * kPointerSize); 3500 3501 // Do the runtime call to allocate the arguments object. 3502 __ bind(&runtime); 3503 __ pop(eax); // Remove saved parameter count. 3504 __ mov(Operand(esp, 1 * kPointerSize), ecx); // Patch argument count. 3505 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 3506 } 3507 3508 3509 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { 3510 // esp[0] : return address 3511 // esp[4] : number of parameters 3512 // esp[8] : receiver displacement 3513 // esp[12] : function 3514 3515 // Check if the calling frame is an arguments adaptor frame. 3516 Label adaptor_frame, try_allocate, runtime; 3517 __ mov(edx, Operand(ebp, StandardFrameConstants::kCallerFPOffset)); 3518 __ mov(ecx, Operand(edx, StandardFrameConstants::kContextOffset)); 3519 __ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); 3520 __ j(equal, &adaptor_frame, Label::kNear); 3521 3522 // Get the length from the frame. 3523 __ mov(ecx, Operand(esp, 1 * kPointerSize)); 3524 __ jmp(&try_allocate, Label::kNear); 3525 3526 // Patch the arguments.length and the parameters pointer. 3527 __ bind(&adaptor_frame); 3528 __ mov(ecx, Operand(edx, ArgumentsAdaptorFrameConstants::kLengthOffset)); 3529 __ mov(Operand(esp, 1 * kPointerSize), ecx); 3530 __ lea(edx, Operand(edx, ecx, times_2, 3531 StandardFrameConstants::kCallerSPOffset)); 3532 __ mov(Operand(esp, 2 * kPointerSize), edx); 3533 3534 // Try the new space allocation. Start out with computing the size of 3535 // the arguments object and the elements array. 3536 Label add_arguments_object; 3537 __ bind(&try_allocate); 3538 __ test(ecx, ecx); 3539 __ j(zero, &add_arguments_object, Label::kNear); 3540 __ lea(ecx, Operand(ecx, times_2, FixedArray::kHeaderSize)); 3541 __ bind(&add_arguments_object); 3542 __ add(ecx, Immediate(Heap::kArgumentsObjectSizeStrict)); 3543 3544 // Do the allocation of both objects in one go. 3545 __ AllocateInNewSpace(ecx, eax, edx, ebx, &runtime, TAG_OBJECT); 3546 3547 // Get the arguments boilerplate from the current (global) context. 3548 __ mov(edi, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); 3549 __ mov(edi, FieldOperand(edi, GlobalObject::kGlobalContextOffset)); 3550 const int offset = 3551 Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX); 3552 __ mov(edi, Operand(edi, offset)); 3553 3554 // Copy the JS object part. 3555 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { 3556 __ mov(ebx, FieldOperand(edi, i)); 3557 __ mov(FieldOperand(eax, i), ebx); 3558 } 3559 3560 // Get the length (smi tagged) and set that as an in-object property too. 3561 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); 3562 __ mov(ecx, Operand(esp, 1 * kPointerSize)); 3563 __ mov(FieldOperand(eax, JSObject::kHeaderSize + 3564 Heap::kArgumentsLengthIndex * kPointerSize), 3565 ecx); 3566 3567 // If there are no actual arguments, we're done. 3568 Label done; 3569 __ test(ecx, ecx); 3570 __ j(zero, &done, Label::kNear); 3571 3572 // Get the parameters pointer from the stack. 3573 __ mov(edx, Operand(esp, 2 * kPointerSize)); 3574 3575 // Set up the elements pointer in the allocated arguments object and 3576 // initialize the header in the elements fixed array. 3577 __ lea(edi, Operand(eax, Heap::kArgumentsObjectSizeStrict)); 3578 __ mov(FieldOperand(eax, JSObject::kElementsOffset), edi); 3579 __ mov(FieldOperand(edi, FixedArray::kMapOffset), 3580 Immediate(FACTORY->fixed_array_map())); 3581 3582 __ mov(FieldOperand(edi, FixedArray::kLengthOffset), ecx); 3583 // Untag the length for the loop below. 3584 __ SmiUntag(ecx); 3585 3586 // Copy the fixed array slots. 3587 Label loop; 3588 __ bind(&loop); 3589 __ mov(ebx, Operand(edx, -1 * kPointerSize)); // Skip receiver. 3590 __ mov(FieldOperand(edi, FixedArray::kHeaderSize), ebx); 3591 __ add(edi, Immediate(kPointerSize)); 3592 __ sub(edx, Immediate(kPointerSize)); 3593 __ dec(ecx); 3594 __ j(not_zero, &loop); 3595 3596 // Return and remove the on-stack parameters. 3597 __ bind(&done); 3598 __ ret(3 * kPointerSize); 3599 3600 // Do the runtime call to allocate the arguments object. 3601 __ bind(&runtime); 3602 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); 3603 } 3604 3605 3606 void RegExpExecStub::Generate(MacroAssembler* masm) { 3607 // Just jump directly to runtime if native RegExp is not selected at compile 3608 // time or if regexp entry in generated code is turned off runtime switch or 3609 // at compilation. 3610 #ifdef V8_INTERPRETED_REGEXP 3611 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 3612 #else // V8_INTERPRETED_REGEXP 3613 3614 // Stack frame on entry. 3615 // esp[0]: return address 3616 // esp[4]: last_match_info (expected JSArray) 3617 // esp[8]: previous index 3618 // esp[12]: subject string 3619 // esp[16]: JSRegExp object 3620 3621 static const int kLastMatchInfoOffset = 1 * kPointerSize; 3622 static const int kPreviousIndexOffset = 2 * kPointerSize; 3623 static const int kSubjectOffset = 3 * kPointerSize; 3624 static const int kJSRegExpOffset = 4 * kPointerSize; 3625 3626 Label runtime, invoke_regexp; 3627 3628 // Ensure that a RegExp stack is allocated. 3629 ExternalReference address_of_regexp_stack_memory_address = 3630 ExternalReference::address_of_regexp_stack_memory_address( 3631 masm->isolate()); 3632 ExternalReference address_of_regexp_stack_memory_size = 3633 ExternalReference::address_of_regexp_stack_memory_size(masm->isolate()); 3634 __ mov(ebx, Operand::StaticVariable(address_of_regexp_stack_memory_size)); 3635 __ test(ebx, ebx); 3636 __ j(zero, &runtime); 3637 3638 // Check that the first argument is a JSRegExp object. 3639 __ mov(eax, Operand(esp, kJSRegExpOffset)); 3640 STATIC_ASSERT(kSmiTag == 0); 3641 __ JumpIfSmi(eax, &runtime); 3642 __ CmpObjectType(eax, JS_REGEXP_TYPE, ecx); 3643 __ j(not_equal, &runtime); 3644 // Check that the RegExp has been compiled (data contains a fixed array). 3645 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); 3646 if (FLAG_debug_code) { 3647 __ test(ecx, Immediate(kSmiTagMask)); 3648 __ Check(not_zero, "Unexpected type for RegExp data, FixedArray expected"); 3649 __ CmpObjectType(ecx, FIXED_ARRAY_TYPE, ebx); 3650 __ Check(equal, "Unexpected type for RegExp data, FixedArray expected"); 3651 } 3652 3653 // ecx: RegExp data (FixedArray) 3654 // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP. 3655 __ mov(ebx, FieldOperand(ecx, JSRegExp::kDataTagOffset)); 3656 __ cmp(ebx, Immediate(Smi::FromInt(JSRegExp::IRREGEXP))); 3657 __ j(not_equal, &runtime); 3658 3659 // ecx: RegExp data (FixedArray) 3660 // Check that the number of captures fit in the static offsets vector buffer. 3661 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); 3662 // Calculate number of capture registers (number_of_captures + 1) * 2. This 3663 // uses the asumption that smis are 2 * their untagged value. 3664 STATIC_ASSERT(kSmiTag == 0); 3665 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 3666 __ add(edx, Immediate(2)); // edx was a smi. 3667 // Check that the static offsets vector buffer is large enough. 3668 __ cmp(edx, OffsetsVector::kStaticOffsetsVectorSize); 3669 __ j(above, &runtime); 3670 3671 // ecx: RegExp data (FixedArray) 3672 // edx: Number of capture registers 3673 // Check that the second argument is a string. 3674 __ mov(eax, Operand(esp, kSubjectOffset)); 3675 __ JumpIfSmi(eax, &runtime); 3676 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); 3677 __ j(NegateCondition(is_string), &runtime); 3678 // Get the length of the string to ebx. 3679 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); 3680 3681 // ebx: Length of subject string as a smi 3682 // ecx: RegExp data (FixedArray) 3683 // edx: Number of capture registers 3684 // Check that the third argument is a positive smi less than the subject 3685 // string length. A negative value will be greater (unsigned comparison). 3686 __ mov(eax, Operand(esp, kPreviousIndexOffset)); 3687 __ JumpIfNotSmi(eax, &runtime); 3688 __ cmp(eax, ebx); 3689 __ j(above_equal, &runtime); 3690 3691 // ecx: RegExp data (FixedArray) 3692 // edx: Number of capture registers 3693 // Check that the fourth object is a JSArray object. 3694 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 3695 __ JumpIfSmi(eax, &runtime); 3696 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx); 3697 __ j(not_equal, &runtime); 3698 // Check that the JSArray is in fast case. 3699 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); 3700 __ mov(eax, FieldOperand(ebx, HeapObject::kMapOffset)); 3701 Factory* factory = masm->isolate()->factory(); 3702 __ cmp(eax, factory->fixed_array_map()); 3703 __ j(not_equal, &runtime); 3704 // Check that the last match info has space for the capture registers and the 3705 // additional information. 3706 __ mov(eax, FieldOperand(ebx, FixedArray::kLengthOffset)); 3707 __ SmiUntag(eax); 3708 __ add(edx, Immediate(RegExpImpl::kLastMatchOverhead)); 3709 __ cmp(edx, eax); 3710 __ j(greater, &runtime); 3711 3712 // Reset offset for possibly sliced string. 3713 __ Set(edi, Immediate(0)); 3714 // ecx: RegExp data (FixedArray) 3715 // Check the representation and encoding of the subject string. 3716 Label seq_ascii_string, seq_two_byte_string, check_code; 3717 __ mov(eax, Operand(esp, kSubjectOffset)); 3718 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 3719 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 3720 // First check for flat two byte string. 3721 __ and_(ebx, kIsNotStringMask | 3722 kStringRepresentationMask | 3723 kStringEncodingMask | 3724 kShortExternalStringMask); 3725 STATIC_ASSERT((kStringTag | kSeqStringTag | kTwoByteStringTag) == 0); 3726 __ j(zero, &seq_two_byte_string, Label::kNear); 3727 // Any other flat string must be a flat ASCII string. None of the following 3728 // string type tests will succeed if subject is not a string or a short 3729 // external string. 3730 __ and_(ebx, Immediate(kIsNotStringMask | 3731 kStringRepresentationMask | 3732 kShortExternalStringMask)); 3733 __ j(zero, &seq_ascii_string, Label::kNear); 3734 3735 // ebx: whether subject is a string and if yes, its string representation 3736 // Check for flat cons string or sliced string. 3737 // A flat cons string is a cons string where the second part is the empty 3738 // string. In that case the subject string is just the first part of the cons 3739 // string. Also in this case the first part of the cons string is known to be 3740 // a sequential string or an external string. 3741 // In the case of a sliced string its offset has to be taken into account. 3742 Label cons_string, external_string, check_encoding; 3743 STATIC_ASSERT(kConsStringTag < kExternalStringTag); 3744 STATIC_ASSERT(kSlicedStringTag > kExternalStringTag); 3745 STATIC_ASSERT(kIsNotStringMask > kExternalStringTag); 3746 STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag); 3747 __ cmp(ebx, Immediate(kExternalStringTag)); 3748 __ j(less, &cons_string); 3749 __ j(equal, &external_string); 3750 3751 // Catch non-string subject or short external string. 3752 STATIC_ASSERT(kNotStringTag != 0 && kShortExternalStringTag !=0); 3753 __ test(ebx, Immediate(kIsNotStringMask | kShortExternalStringTag)); 3754 __ j(not_zero, &runtime); 3755 3756 // String is sliced. 3757 __ mov(edi, FieldOperand(eax, SlicedString::kOffsetOffset)); 3758 __ mov(eax, FieldOperand(eax, SlicedString::kParentOffset)); 3759 // edi: offset of sliced string, smi-tagged. 3760 // eax: parent string. 3761 __ jmp(&check_encoding, Label::kNear); 3762 // String is a cons string, check whether it is flat. 3763 __ bind(&cons_string); 3764 __ cmp(FieldOperand(eax, ConsString::kSecondOffset), factory->empty_string()); 3765 __ j(not_equal, &runtime); 3766 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); 3767 __ bind(&check_encoding); 3768 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 3769 // eax: first part of cons string or parent of sliced string. 3770 // ebx: map of first part of cons string or map of parent of sliced string. 3771 // Is first part of cons or parent of slice a flat two byte string? 3772 __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), 3773 kStringRepresentationMask | kStringEncodingMask); 3774 STATIC_ASSERT((kSeqStringTag | kTwoByteStringTag) == 0); 3775 __ j(zero, &seq_two_byte_string, Label::kNear); 3776 // Any other flat string must be sequential ASCII or external. 3777 __ test_b(FieldOperand(ebx, Map::kInstanceTypeOffset), 3778 kStringRepresentationMask); 3779 __ j(not_zero, &external_string); 3780 3781 __ bind(&seq_ascii_string); 3782 // eax: subject string (flat ASCII) 3783 // ecx: RegExp data (FixedArray) 3784 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataAsciiCodeOffset)); 3785 __ Set(ecx, Immediate(1)); // Type is ASCII. 3786 __ jmp(&check_code, Label::kNear); 3787 3788 __ bind(&seq_two_byte_string); 3789 // eax: subject string (flat two byte) 3790 // ecx: RegExp data (FixedArray) 3791 __ mov(edx, FieldOperand(ecx, JSRegExp::kDataUC16CodeOffset)); 3792 __ Set(ecx, Immediate(0)); // Type is two byte. 3793 3794 __ bind(&check_code); 3795 // Check that the irregexp code has been generated for the actual string 3796 // encoding. If it has, the field contains a code object otherwise it contains 3797 // a smi (code flushing support). 3798 __ JumpIfSmi(edx, &runtime); 3799 3800 // eax: subject string 3801 // edx: code 3802 // ecx: encoding of subject string (1 if ASCII, 0 if two_byte); 3803 // Load used arguments before starting to push arguments for call to native 3804 // RegExp code to avoid handling changing stack height. 3805 __ mov(ebx, Operand(esp, kPreviousIndexOffset)); 3806 __ SmiUntag(ebx); // Previous index from smi. 3807 3808 // eax: subject string 3809 // ebx: previous index 3810 // edx: code 3811 // ecx: encoding of subject string (1 if ASCII 0 if two_byte); 3812 // All checks done. Now push arguments for native regexp code. 3813 Counters* counters = masm->isolate()->counters(); 3814 __ IncrementCounter(counters->regexp_entry_native(), 1); 3815 3816 // Isolates: note we add an additional parameter here (isolate pointer). 3817 static const int kRegExpExecuteArguments = 8; 3818 __ EnterApiExitFrame(kRegExpExecuteArguments); 3819 3820 // Argument 8: Pass current isolate address. 3821 __ mov(Operand(esp, 7 * kPointerSize), 3822 Immediate(ExternalReference::isolate_address())); 3823 3824 // Argument 7: Indicate that this is a direct call from JavaScript. 3825 __ mov(Operand(esp, 6 * kPointerSize), Immediate(1)); 3826 3827 // Argument 6: Start (high end) of backtracking stack memory area. 3828 __ mov(esi, Operand::StaticVariable(address_of_regexp_stack_memory_address)); 3829 __ add(esi, Operand::StaticVariable(address_of_regexp_stack_memory_size)); 3830 __ mov(Operand(esp, 5 * kPointerSize), esi); 3831 3832 // Argument 5: static offsets vector buffer. 3833 __ mov(Operand(esp, 4 * kPointerSize), 3834 Immediate(ExternalReference::address_of_static_offsets_vector( 3835 masm->isolate()))); 3836 3837 // Argument 2: Previous index. 3838 __ mov(Operand(esp, 1 * kPointerSize), ebx); 3839 3840 // Argument 1: Original subject string. 3841 // The original subject is in the previous stack frame. Therefore we have to 3842 // use ebp, which points exactly to one pointer size below the previous esp. 3843 // (Because creating a new stack frame pushes the previous ebp onto the stack 3844 // and thereby moves up esp by one kPointerSize.) 3845 __ mov(esi, Operand(ebp, kSubjectOffset + kPointerSize)); 3846 __ mov(Operand(esp, 0 * kPointerSize), esi); 3847 3848 // esi: original subject string 3849 // eax: underlying subject string 3850 // ebx: previous index 3851 // ecx: encoding of subject string (1 if ASCII 0 if two_byte); 3852 // edx: code 3853 // Argument 4: End of string data 3854 // Argument 3: Start of string data 3855 // Prepare start and end index of the input. 3856 // Load the length from the original sliced string if that is the case. 3857 __ mov(esi, FieldOperand(esi, String::kLengthOffset)); 3858 __ add(esi, edi); // Calculate input end wrt offset. 3859 __ SmiUntag(edi); 3860 __ add(ebx, edi); // Calculate input start wrt offset. 3861 3862 // ebx: start index of the input string 3863 // esi: end index of the input string 3864 Label setup_two_byte, setup_rest; 3865 __ test(ecx, ecx); 3866 __ j(zero, &setup_two_byte, Label::kNear); 3867 __ SmiUntag(esi); 3868 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqAsciiString::kHeaderSize)); 3869 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. 3870 __ lea(ecx, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); 3871 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. 3872 __ jmp(&setup_rest, Label::kNear); 3873 3874 __ bind(&setup_two_byte); 3875 STATIC_ASSERT(kSmiTag == 0); 3876 STATIC_ASSERT(kSmiTagSize == 1); // esi is smi (powered by 2). 3877 __ lea(ecx, FieldOperand(eax, esi, times_1, SeqTwoByteString::kHeaderSize)); 3878 __ mov(Operand(esp, 3 * kPointerSize), ecx); // Argument 4. 3879 __ lea(ecx, FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); 3880 __ mov(Operand(esp, 2 * kPointerSize), ecx); // Argument 3. 3881 3882 __ bind(&setup_rest); 3883 3884 // Locate the code entry and call it. 3885 __ add(edx, Immediate(Code::kHeaderSize - kHeapObjectTag)); 3886 __ call(edx); 3887 3888 // Drop arguments and come back to JS mode. 3889 __ LeaveApiExitFrame(); 3890 3891 // Check the result. 3892 Label success; 3893 __ cmp(eax, NativeRegExpMacroAssembler::SUCCESS); 3894 __ j(equal, &success); 3895 Label failure; 3896 __ cmp(eax, NativeRegExpMacroAssembler::FAILURE); 3897 __ j(equal, &failure); 3898 __ cmp(eax, NativeRegExpMacroAssembler::EXCEPTION); 3899 // If not exception it can only be retry. Handle that in the runtime system. 3900 __ j(not_equal, &runtime); 3901 // Result must now be exception. If there is no pending exception already a 3902 // stack overflow (on the backtrack stack) was detected in RegExp code but 3903 // haven't created the exception yet. Handle that in the runtime system. 3904 // TODO(592): Rerunning the RegExp to get the stack overflow exception. 3905 ExternalReference pending_exception(Isolate::kPendingExceptionAddress, 3906 masm->isolate()); 3907 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value())); 3908 __ mov(eax, Operand::StaticVariable(pending_exception)); 3909 __ cmp(edx, eax); 3910 __ j(equal, &runtime); 3911 // For exception, throw the exception again. 3912 3913 // Clear the pending exception variable. 3914 __ mov(Operand::StaticVariable(pending_exception), edx); 3915 3916 // Special handling of termination exceptions which are uncatchable 3917 // by javascript code. 3918 __ cmp(eax, factory->termination_exception()); 3919 Label throw_termination_exception; 3920 __ j(equal, &throw_termination_exception, Label::kNear); 3921 3922 // Handle normal exception by following handler chain. 3923 __ Throw(eax); 3924 3925 __ bind(&throw_termination_exception); 3926 __ ThrowUncatchable(eax); 3927 3928 __ bind(&failure); 3929 // For failure to match, return null. 3930 __ mov(eax, factory->null_value()); 3931 __ ret(4 * kPointerSize); 3932 3933 // Load RegExp data. 3934 __ bind(&success); 3935 __ mov(eax, Operand(esp, kJSRegExpOffset)); 3936 __ mov(ecx, FieldOperand(eax, JSRegExp::kDataOffset)); 3937 __ mov(edx, FieldOperand(ecx, JSRegExp::kIrregexpCaptureCountOffset)); 3938 // Calculate number of capture registers (number_of_captures + 1) * 2. 3939 STATIC_ASSERT(kSmiTag == 0); 3940 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 3941 __ add(edx, Immediate(2)); // edx was a smi. 3942 3943 // edx: Number of capture registers 3944 // Load last_match_info which is still known to be a fast case JSArray. 3945 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 3946 __ mov(ebx, FieldOperand(eax, JSArray::kElementsOffset)); 3947 3948 // ebx: last_match_info backing store (FixedArray) 3949 // edx: number of capture registers 3950 // Store the capture count. 3951 __ SmiTag(edx); // Number of capture registers to smi. 3952 __ mov(FieldOperand(ebx, RegExpImpl::kLastCaptureCountOffset), edx); 3953 __ SmiUntag(edx); // Number of capture registers back from smi. 3954 // Store last subject and last input. 3955 __ mov(eax, Operand(esp, kSubjectOffset)); 3956 __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax); 3957 __ RecordWriteField(ebx, 3958 RegExpImpl::kLastSubjectOffset, 3959 eax, 3960 edi, 3961 kDontSaveFPRegs); 3962 __ mov(eax, Operand(esp, kSubjectOffset)); 3963 __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax); 3964 __ RecordWriteField(ebx, 3965 RegExpImpl::kLastInputOffset, 3966 eax, 3967 edi, 3968 kDontSaveFPRegs); 3969 3970 // Get the static offsets vector filled by the native regexp code. 3971 ExternalReference address_of_static_offsets_vector = 3972 ExternalReference::address_of_static_offsets_vector(masm->isolate()); 3973 __ mov(ecx, Immediate(address_of_static_offsets_vector)); 3974 3975 // ebx: last_match_info backing store (FixedArray) 3976 // ecx: offsets vector 3977 // edx: number of capture registers 3978 Label next_capture, done; 3979 // Capture register counter starts from number of capture registers and 3980 // counts down until wraping after zero. 3981 __ bind(&next_capture); 3982 __ sub(edx, Immediate(1)); 3983 __ j(negative, &done, Label::kNear); 3984 // Read the value from the static offsets vector buffer. 3985 __ mov(edi, Operand(ecx, edx, times_int_size, 0)); 3986 __ SmiTag(edi); 3987 // Store the smi value in the last match info. 3988 __ mov(FieldOperand(ebx, 3989 edx, 3990 times_pointer_size, 3991 RegExpImpl::kFirstCaptureOffset), 3992 edi); 3993 __ jmp(&next_capture); 3994 __ bind(&done); 3995 3996 // Return last match info. 3997 __ mov(eax, Operand(esp, kLastMatchInfoOffset)); 3998 __ ret(4 * kPointerSize); 3999 4000 // External string. Short external strings have already been ruled out. 4001 // eax: subject string (expected to be external) 4002 // ebx: scratch 4003 __ bind(&external_string); 4004 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 4005 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 4006 if (FLAG_debug_code) { 4007 // Assert that we do not have a cons or slice (indirect strings) here. 4008 // Sequential strings have already been ruled out. 4009 __ test_b(ebx, kIsIndirectStringMask); 4010 __ Assert(zero, "external string expected, but not found"); 4011 } 4012 __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); 4013 // Move the pointer so that offset-wise, it looks like a sequential string. 4014 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); 4015 __ sub(eax, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 4016 STATIC_ASSERT(kTwoByteStringTag == 0); 4017 __ test_b(ebx, kStringEncodingMask); 4018 __ j(not_zero, &seq_ascii_string); 4019 __ jmp(&seq_two_byte_string); 4020 4021 // Do the runtime call to execute the regexp. 4022 __ bind(&runtime); 4023 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); 4024 #endif // V8_INTERPRETED_REGEXP 4025 } 4026 4027 4028 void RegExpConstructResultStub::Generate(MacroAssembler* masm) { 4029 const int kMaxInlineLength = 100; 4030 Label slowcase; 4031 Label done; 4032 __ mov(ebx, Operand(esp, kPointerSize * 3)); 4033 __ JumpIfNotSmi(ebx, &slowcase); 4034 __ cmp(ebx, Immediate(Smi::FromInt(kMaxInlineLength))); 4035 __ j(above, &slowcase); 4036 // Smi-tagging is equivalent to multiplying by 2. 4037 STATIC_ASSERT(kSmiTag == 0); 4038 STATIC_ASSERT(kSmiTagSize == 1); 4039 // Allocate RegExpResult followed by FixedArray with size in ebx. 4040 // JSArray: [Map][empty properties][Elements][Length-smi][index][input] 4041 // Elements: [Map][Length][..elements..] 4042 __ AllocateInNewSpace(JSRegExpResult::kSize + FixedArray::kHeaderSize, 4043 times_half_pointer_size, 4044 ebx, // In: Number of elements (times 2, being a smi) 4045 eax, // Out: Start of allocation (tagged). 4046 ecx, // Out: End of allocation. 4047 edx, // Scratch register 4048 &slowcase, 4049 TAG_OBJECT); 4050 // eax: Start of allocated area, object-tagged. 4051 4052 // Set JSArray map to global.regexp_result_map(). 4053 // Set empty properties FixedArray. 4054 // Set elements to point to FixedArray allocated right after the JSArray. 4055 // Interleave operations for better latency. 4056 __ mov(edx, ContextOperand(esi, Context::GLOBAL_INDEX)); 4057 Factory* factory = masm->isolate()->factory(); 4058 __ mov(ecx, Immediate(factory->empty_fixed_array())); 4059 __ lea(ebx, Operand(eax, JSRegExpResult::kSize)); 4060 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalContextOffset)); 4061 __ mov(FieldOperand(eax, JSObject::kElementsOffset), ebx); 4062 __ mov(FieldOperand(eax, JSObject::kPropertiesOffset), ecx); 4063 __ mov(edx, ContextOperand(edx, Context::REGEXP_RESULT_MAP_INDEX)); 4064 __ mov(FieldOperand(eax, HeapObject::kMapOffset), edx); 4065 4066 // Set input, index and length fields from arguments. 4067 __ mov(ecx, Operand(esp, kPointerSize * 1)); 4068 __ mov(FieldOperand(eax, JSRegExpResult::kInputOffset), ecx); 4069 __ mov(ecx, Operand(esp, kPointerSize * 2)); 4070 __ mov(FieldOperand(eax, JSRegExpResult::kIndexOffset), ecx); 4071 __ mov(ecx, Operand(esp, kPointerSize * 3)); 4072 __ mov(FieldOperand(eax, JSArray::kLengthOffset), ecx); 4073 4074 // Fill out the elements FixedArray. 4075 // eax: JSArray. 4076 // ebx: FixedArray. 4077 // ecx: Number of elements in array, as smi. 4078 4079 // Set map. 4080 __ mov(FieldOperand(ebx, HeapObject::kMapOffset), 4081 Immediate(factory->fixed_array_map())); 4082 // Set length. 4083 __ mov(FieldOperand(ebx, FixedArray::kLengthOffset), ecx); 4084 // Fill contents of fixed-array with the-hole. 4085 __ SmiUntag(ecx); 4086 __ mov(edx, Immediate(factory->the_hole_value())); 4087 __ lea(ebx, FieldOperand(ebx, FixedArray::kHeaderSize)); 4088 // Fill fixed array elements with hole. 4089 // eax: JSArray. 4090 // ecx: Number of elements to fill. 4091 // ebx: Start of elements in FixedArray. 4092 // edx: the hole. 4093 Label loop; 4094 __ test(ecx, ecx); 4095 __ bind(&loop); 4096 __ j(less_equal, &done, Label::kNear); // Jump if ecx is negative or zero. 4097 __ sub(ecx, Immediate(1)); 4098 __ mov(Operand(ebx, ecx, times_pointer_size, 0), edx); 4099 __ jmp(&loop); 4100 4101 __ bind(&done); 4102 __ ret(3 * kPointerSize); 4103 4104 __ bind(&slowcase); 4105 __ TailCallRuntime(Runtime::kRegExpConstructResult, 3, 1); 4106 } 4107 4108 4109 void NumberToStringStub::GenerateLookupNumberStringCache(MacroAssembler* masm, 4110 Register object, 4111 Register result, 4112 Register scratch1, 4113 Register scratch2, 4114 bool object_is_smi, 4115 Label* not_found) { 4116 // Use of registers. Register result is used as a temporary. 4117 Register number_string_cache = result; 4118 Register mask = scratch1; 4119 Register scratch = scratch2; 4120 4121 // Load the number string cache. 4122 ExternalReference roots_array_start = 4123 ExternalReference::roots_array_start(masm->isolate()); 4124 __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex)); 4125 __ mov(number_string_cache, 4126 Operand::StaticArray(scratch, times_pointer_size, roots_array_start)); 4127 // Make the hash mask from the length of the number string cache. It 4128 // contains two elements (number and string) for each cache entry. 4129 __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset)); 4130 __ shr(mask, kSmiTagSize + 1); // Untag length and divide it by two. 4131 __ sub(mask, Immediate(1)); // Make mask. 4132 4133 // Calculate the entry in the number string cache. The hash value in the 4134 // number string cache for smis is just the smi value, and the hash for 4135 // doubles is the xor of the upper and lower words. See 4136 // Heap::GetNumberStringCache. 4137 Label smi_hash_calculated; 4138 Label load_result_from_cache; 4139 if (object_is_smi) { 4140 __ mov(scratch, object); 4141 __ SmiUntag(scratch); 4142 } else { 4143 Label not_smi; 4144 STATIC_ASSERT(kSmiTag == 0); 4145 __ JumpIfNotSmi(object, ¬_smi, Label::kNear); 4146 __ mov(scratch, object); 4147 __ SmiUntag(scratch); 4148 __ jmp(&smi_hash_calculated, Label::kNear); 4149 __ bind(¬_smi); 4150 __ cmp(FieldOperand(object, HeapObject::kMapOffset), 4151 masm->isolate()->factory()->heap_number_map()); 4152 __ j(not_equal, not_found); 4153 STATIC_ASSERT(8 == kDoubleSize); 4154 __ mov(scratch, FieldOperand(object, HeapNumber::kValueOffset)); 4155 __ xor_(scratch, FieldOperand(object, HeapNumber::kValueOffset + 4)); 4156 // Object is heap number and hash is now in scratch. Calculate cache index. 4157 __ and_(scratch, mask); 4158 Register index = scratch; 4159 Register probe = mask; 4160 __ mov(probe, 4161 FieldOperand(number_string_cache, 4162 index, 4163 times_twice_pointer_size, 4164 FixedArray::kHeaderSize)); 4165 __ JumpIfSmi(probe, not_found); 4166 if (CpuFeatures::IsSupported(SSE2)) { 4167 CpuFeatures::Scope fscope(SSE2); 4168 __ movdbl(xmm0, FieldOperand(object, HeapNumber::kValueOffset)); 4169 __ movdbl(xmm1, FieldOperand(probe, HeapNumber::kValueOffset)); 4170 __ ucomisd(xmm0, xmm1); 4171 } else { 4172 __ fld_d(FieldOperand(object, HeapNumber::kValueOffset)); 4173 __ fld_d(FieldOperand(probe, HeapNumber::kValueOffset)); 4174 __ FCmp(); 4175 } 4176 __ j(parity_even, not_found); // Bail out if NaN is involved. 4177 __ j(not_equal, not_found); // The cache did not contain this value. 4178 __ jmp(&load_result_from_cache, Label::kNear); 4179 } 4180 4181 __ bind(&smi_hash_calculated); 4182 // Object is smi and hash is now in scratch. Calculate cache index. 4183 __ and_(scratch, mask); 4184 Register index = scratch; 4185 // Check if the entry is the smi we are looking for. 4186 __ cmp(object, 4187 FieldOperand(number_string_cache, 4188 index, 4189 times_twice_pointer_size, 4190 FixedArray::kHeaderSize)); 4191 __ j(not_equal, not_found); 4192 4193 // Get the result from the cache. 4194 __ bind(&load_result_from_cache); 4195 __ mov(result, 4196 FieldOperand(number_string_cache, 4197 index, 4198 times_twice_pointer_size, 4199 FixedArray::kHeaderSize + kPointerSize)); 4200 Counters* counters = masm->isolate()->counters(); 4201 __ IncrementCounter(counters->number_to_string_native(), 1); 4202 } 4203 4204 4205 void NumberToStringStub::Generate(MacroAssembler* masm) { 4206 Label runtime; 4207 4208 __ mov(ebx, Operand(esp, kPointerSize)); 4209 4210 // Generate code to lookup number in the number string cache. 4211 GenerateLookupNumberStringCache(masm, ebx, eax, ecx, edx, false, &runtime); 4212 __ ret(1 * kPointerSize); 4213 4214 __ bind(&runtime); 4215 // Handle number to string in the runtime system if not found in the cache. 4216 __ TailCallRuntime(Runtime::kNumberToStringSkipCache, 1, 1); 4217 } 4218 4219 4220 static int NegativeComparisonResult(Condition cc) { 4221 ASSERT(cc != equal); 4222 ASSERT((cc == less) || (cc == less_equal) 4223 || (cc == greater) || (cc == greater_equal)); 4224 return (cc == greater || cc == greater_equal) ? LESS : GREATER; 4225 } 4226 4227 void CompareStub::Generate(MacroAssembler* masm) { 4228 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 4229 4230 Label check_unequal_objects; 4231 4232 // Compare two smis if required. 4233 if (include_smi_compare_) { 4234 Label non_smi, smi_done; 4235 __ mov(ecx, edx); 4236 __ or_(ecx, eax); 4237 __ JumpIfNotSmi(ecx, &non_smi, Label::kNear); 4238 __ sub(edx, eax); // Return on the result of the subtraction. 4239 __ j(no_overflow, &smi_done, Label::kNear); 4240 __ not_(edx); // Correct sign in case of overflow. edx is never 0 here. 4241 __ bind(&smi_done); 4242 __ mov(eax, edx); 4243 __ ret(0); 4244 __ bind(&non_smi); 4245 } else if (FLAG_debug_code) { 4246 __ mov(ecx, edx); 4247 __ or_(ecx, eax); 4248 __ test(ecx, Immediate(kSmiTagMask)); 4249 __ Assert(not_zero, "Unexpected smi operands."); 4250 } 4251 4252 // NOTICE! This code is only reached after a smi-fast-case check, so 4253 // it is certain that at least one operand isn't a smi. 4254 4255 // Identical objects can be compared fast, but there are some tricky cases 4256 // for NaN and undefined. 4257 { 4258 Label not_identical; 4259 __ cmp(eax, edx); 4260 __ j(not_equal, ¬_identical); 4261 4262 if (cc_ != equal) { 4263 // Check for undefined. undefined OP undefined is false even though 4264 // undefined == undefined. 4265 Label check_for_nan; 4266 __ cmp(edx, masm->isolate()->factory()->undefined_value()); 4267 __ j(not_equal, &check_for_nan, Label::kNear); 4268 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 4269 __ ret(0); 4270 __ bind(&check_for_nan); 4271 } 4272 4273 // Test for NaN. Sadly, we can't just compare to factory->nan_value(), 4274 // so we do the second best thing - test it ourselves. 4275 // Note: if cc_ != equal, never_nan_nan_ is not used. 4276 if (never_nan_nan_ && (cc_ == equal)) { 4277 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 4278 __ ret(0); 4279 } else { 4280 Label heap_number; 4281 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), 4282 Immediate(masm->isolate()->factory()->heap_number_map())); 4283 __ j(equal, &heap_number, Label::kNear); 4284 if (cc_ != equal) { 4285 // Call runtime on identical JSObjects. Otherwise return equal. 4286 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 4287 __ j(above_equal, ¬_identical); 4288 } 4289 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 4290 __ ret(0); 4291 4292 __ bind(&heap_number); 4293 // It is a heap number, so return non-equal if it's NaN and equal if 4294 // it's not NaN. 4295 // The representation of NaN values has all exponent bits (52..62) set, 4296 // and not all mantissa bits (0..51) clear. 4297 // We only accept QNaNs, which have bit 51 set. 4298 // Read top bits of double representation (second word of value). 4299 4300 // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e., 4301 // all bits in the mask are set. We only need to check the word 4302 // that contains the exponent and high bit of the mantissa. 4303 STATIC_ASSERT(((kQuietNaNHighBitsMask << 1) & 0x80000000u) != 0); 4304 __ mov(edx, FieldOperand(edx, HeapNumber::kExponentOffset)); 4305 __ Set(eax, Immediate(0)); 4306 // Shift value and mask so kQuietNaNHighBitsMask applies to topmost 4307 // bits. 4308 __ add(edx, edx); 4309 __ cmp(edx, kQuietNaNHighBitsMask << 1); 4310 if (cc_ == equal) { 4311 STATIC_ASSERT(EQUAL != 1); 4312 __ setcc(above_equal, eax); 4313 __ ret(0); 4314 } else { 4315 Label nan; 4316 __ j(above_equal, &nan, Label::kNear); 4317 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 4318 __ ret(0); 4319 __ bind(&nan); 4320 __ Set(eax, Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 4321 __ ret(0); 4322 } 4323 } 4324 4325 __ bind(¬_identical); 4326 } 4327 4328 // Strict equality can quickly decide whether objects are equal. 4329 // Non-strict object equality is slower, so it is handled later in the stub. 4330 if (cc_ == equal && strict_) { 4331 Label slow; // Fallthrough label. 4332 Label not_smis; 4333 // If we're doing a strict equality comparison, we don't have to do 4334 // type conversion, so we generate code to do fast comparison for objects 4335 // and oddballs. Non-smi numbers and strings still go through the usual 4336 // slow-case code. 4337 // If either is a Smi (we know that not both are), then they can only 4338 // be equal if the other is a HeapNumber. If so, use the slow case. 4339 STATIC_ASSERT(kSmiTag == 0); 4340 ASSERT_EQ(0, Smi::FromInt(0)); 4341 __ mov(ecx, Immediate(kSmiTagMask)); 4342 __ and_(ecx, eax); 4343 __ test(ecx, edx); 4344 __ j(not_zero, ¬_smis, Label::kNear); 4345 // One operand is a smi. 4346 4347 // Check whether the non-smi is a heap number. 4348 STATIC_ASSERT(kSmiTagMask == 1); 4349 // ecx still holds eax & kSmiTag, which is either zero or one. 4350 __ sub(ecx, Immediate(0x01)); 4351 __ mov(ebx, edx); 4352 __ xor_(ebx, eax); 4353 __ and_(ebx, ecx); // ebx holds either 0 or eax ^ edx. 4354 __ xor_(ebx, eax); 4355 // if eax was smi, ebx is now edx, else eax. 4356 4357 // Check if the non-smi operand is a heap number. 4358 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), 4359 Immediate(masm->isolate()->factory()->heap_number_map())); 4360 // If heap number, handle it in the slow case. 4361 __ j(equal, &slow, Label::kNear); 4362 // Return non-equal (ebx is not zero) 4363 __ mov(eax, ebx); 4364 __ ret(0); 4365 4366 __ bind(¬_smis); 4367 // If either operand is a JSObject or an oddball value, then they are not 4368 // equal since their pointers are different 4369 // There is no test for undetectability in strict equality. 4370 4371 // Get the type of the first operand. 4372 // If the first object is a JS object, we have done pointer comparison. 4373 Label first_non_object; 4374 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); 4375 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 4376 __ j(below, &first_non_object, Label::kNear); 4377 4378 // Return non-zero (eax is not zero) 4379 Label return_not_equal; 4380 STATIC_ASSERT(kHeapObjectTag != 0); 4381 __ bind(&return_not_equal); 4382 __ ret(0); 4383 4384 __ bind(&first_non_object); 4385 // Check for oddballs: true, false, null, undefined. 4386 __ CmpInstanceType(ecx, ODDBALL_TYPE); 4387 __ j(equal, &return_not_equal); 4388 4389 __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ecx); 4390 __ j(above_equal, &return_not_equal); 4391 4392 // Check for oddballs: true, false, null, undefined. 4393 __ CmpInstanceType(ecx, ODDBALL_TYPE); 4394 __ j(equal, &return_not_equal); 4395 4396 // Fall through to the general case. 4397 __ bind(&slow); 4398 } 4399 4400 // Generate the number comparison code. 4401 if (include_number_compare_) { 4402 Label non_number_comparison; 4403 Label unordered; 4404 if (CpuFeatures::IsSupported(SSE2)) { 4405 CpuFeatures::Scope use_sse2(SSE2); 4406 CpuFeatures::Scope use_cmov(CMOV); 4407 4408 FloatingPointHelper::LoadSSE2Operands(masm, &non_number_comparison); 4409 __ ucomisd(xmm0, xmm1); 4410 4411 // Don't base result on EFLAGS when a NaN is involved. 4412 __ j(parity_even, &unordered, Label::kNear); 4413 // Return a result of -1, 0, or 1, based on EFLAGS. 4414 __ mov(eax, 0); // equal 4415 __ mov(ecx, Immediate(Smi::FromInt(1))); 4416 __ cmov(above, eax, ecx); 4417 __ mov(ecx, Immediate(Smi::FromInt(-1))); 4418 __ cmov(below, eax, ecx); 4419 __ ret(0); 4420 } else { 4421 FloatingPointHelper::CheckFloatOperands( 4422 masm, &non_number_comparison, ebx); 4423 FloatingPointHelper::LoadFloatOperand(masm, eax); 4424 FloatingPointHelper::LoadFloatOperand(masm, edx); 4425 __ FCmp(); 4426 4427 // Don't base result on EFLAGS when a NaN is involved. 4428 __ j(parity_even, &unordered, Label::kNear); 4429 4430 Label below_label, above_label; 4431 // Return a result of -1, 0, or 1, based on EFLAGS. 4432 __ j(below, &below_label, Label::kNear); 4433 __ j(above, &above_label, Label::kNear); 4434 4435 __ Set(eax, Immediate(0)); 4436 __ ret(0); 4437 4438 __ bind(&below_label); 4439 __ mov(eax, Immediate(Smi::FromInt(-1))); 4440 __ ret(0); 4441 4442 __ bind(&above_label); 4443 __ mov(eax, Immediate(Smi::FromInt(1))); 4444 __ ret(0); 4445 } 4446 4447 // If one of the numbers was NaN, then the result is always false. 4448 // The cc is never not-equal. 4449 __ bind(&unordered); 4450 ASSERT(cc_ != not_equal); 4451 if (cc_ == less || cc_ == less_equal) { 4452 __ mov(eax, Immediate(Smi::FromInt(1))); 4453 } else { 4454 __ mov(eax, Immediate(Smi::FromInt(-1))); 4455 } 4456 __ ret(0); 4457 4458 // The number comparison code did not provide a valid result. 4459 __ bind(&non_number_comparison); 4460 } 4461 4462 // Fast negative check for symbol-to-symbol equality. 4463 Label check_for_strings; 4464 if (cc_ == equal) { 4465 BranchIfNonSymbol(masm, &check_for_strings, eax, ecx); 4466 BranchIfNonSymbol(masm, &check_for_strings, edx, ecx); 4467 4468 // We've already checked for object identity, so if both operands 4469 // are symbols they aren't equal. Register eax already holds a 4470 // non-zero value, which indicates not equal, so just return. 4471 __ ret(0); 4472 } 4473 4474 __ bind(&check_for_strings); 4475 4476 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, 4477 &check_unequal_objects); 4478 4479 // Inline comparison of ASCII strings. 4480 if (cc_ == equal) { 4481 StringCompareStub::GenerateFlatAsciiStringEquals(masm, 4482 edx, 4483 eax, 4484 ecx, 4485 ebx); 4486 } else { 4487 StringCompareStub::GenerateCompareFlatAsciiStrings(masm, 4488 edx, 4489 eax, 4490 ecx, 4491 ebx, 4492 edi); 4493 } 4494 #ifdef DEBUG 4495 __ Abort("Unexpected fall-through from string comparison"); 4496 #endif 4497 4498 __ bind(&check_unequal_objects); 4499 if (cc_ == equal && !strict_) { 4500 // Non-strict equality. Objects are unequal if 4501 // they are both JSObjects and not undetectable, 4502 // and their pointers are different. 4503 Label not_both_objects; 4504 Label return_unequal; 4505 // At most one is a smi, so we can test for smi by adding the two. 4506 // A smi plus a heap object has the low bit set, a heap object plus 4507 // a heap object has the low bit clear. 4508 STATIC_ASSERT(kSmiTag == 0); 4509 STATIC_ASSERT(kSmiTagMask == 1); 4510 __ lea(ecx, Operand(eax, edx, times_1, 0)); 4511 __ test(ecx, Immediate(kSmiTagMask)); 4512 __ j(not_zero, ¬_both_objects, Label::kNear); 4513 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); 4514 __ j(below, ¬_both_objects, Label::kNear); 4515 __ CmpObjectType(edx, FIRST_SPEC_OBJECT_TYPE, ebx); 4516 __ j(below, ¬_both_objects, Label::kNear); 4517 // We do not bail out after this point. Both are JSObjects, and 4518 // they are equal if and only if both are undetectable. 4519 // The and of the undetectable flags is 1 if and only if they are equal. 4520 __ test_b(FieldOperand(ecx, Map::kBitFieldOffset), 4521 1 << Map::kIsUndetectable); 4522 __ j(zero, &return_unequal, Label::kNear); 4523 __ test_b(FieldOperand(ebx, Map::kBitFieldOffset), 4524 1 << Map::kIsUndetectable); 4525 __ j(zero, &return_unequal, Label::kNear); 4526 // The objects are both undetectable, so they both compare as the value 4527 // undefined, and are equal. 4528 __ Set(eax, Immediate(EQUAL)); 4529 __ bind(&return_unequal); 4530 // Return non-equal by returning the non-zero object pointer in eax, 4531 // or return equal if we fell through to here. 4532 __ ret(0); // rax, rdx were pushed 4533 __ bind(¬_both_objects); 4534 } 4535 4536 // Push arguments below the return address. 4537 __ pop(ecx); 4538 __ push(edx); 4539 __ push(eax); 4540 4541 // Figure out which native to call and setup the arguments. 4542 Builtins::JavaScript builtin; 4543 if (cc_ == equal) { 4544 builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS; 4545 } else { 4546 builtin = Builtins::COMPARE; 4547 __ push(Immediate(Smi::FromInt(NegativeComparisonResult(cc_)))); 4548 } 4549 4550 // Restore return address on the stack. 4551 __ push(ecx); 4552 4553 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater) 4554 // tagged as a small integer. 4555 __ InvokeBuiltin(builtin, JUMP_FUNCTION); 4556 } 4557 4558 4559 void CompareStub::BranchIfNonSymbol(MacroAssembler* masm, 4560 Label* label, 4561 Register object, 4562 Register scratch) { 4563 __ JumpIfSmi(object, label); 4564 __ mov(scratch, FieldOperand(object, HeapObject::kMapOffset)); 4565 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); 4566 __ and_(scratch, kIsSymbolMask | kIsNotStringMask); 4567 __ cmp(scratch, kSymbolTag | kStringTag); 4568 __ j(not_equal, label); 4569 } 4570 4571 4572 void StackCheckStub::Generate(MacroAssembler* masm) { 4573 __ TailCallRuntime(Runtime::kStackGuard, 0, 1); 4574 } 4575 4576 4577 void InterruptStub::Generate(MacroAssembler* masm) { 4578 __ TailCallRuntime(Runtime::kInterrupt, 0, 1); 4579 } 4580 4581 4582 static void GenerateRecordCallTarget(MacroAssembler* masm) { 4583 // Cache the called function in a global property cell. Cache states 4584 // are uninitialized, monomorphic (indicated by a JSFunction), and 4585 // megamorphic. 4586 // ebx : cache cell for call target 4587 // edi : the function to call 4588 Isolate* isolate = masm->isolate(); 4589 Label initialize, done; 4590 4591 // Load the cache state into ecx. 4592 __ mov(ecx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); 4593 4594 // A monomorphic cache hit or an already megamorphic state: invoke the 4595 // function without changing the state. 4596 __ cmp(ecx, edi); 4597 __ j(equal, &done, Label::kNear); 4598 __ cmp(ecx, Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); 4599 __ j(equal, &done, Label::kNear); 4600 4601 // A monomorphic miss (i.e, here the cache is not uninitialized) goes 4602 // megamorphic. 4603 __ cmp(ecx, Immediate(TypeFeedbackCells::UninitializedSentinel(isolate))); 4604 __ j(equal, &initialize, Label::kNear); 4605 // MegamorphicSentinel is an immortal immovable object (undefined) so no 4606 // write-barrier is needed. 4607 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), 4608 Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); 4609 __ jmp(&done, Label::kNear); 4610 4611 // An uninitialized cache is patched with the function. 4612 __ bind(&initialize); 4613 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), edi); 4614 // No need for a write barrier here - cells are rescanned. 4615 4616 __ bind(&done); 4617 } 4618 4619 4620 void CallFunctionStub::Generate(MacroAssembler* masm) { 4621 // ebx : cache cell for call target 4622 // edi : the function to call 4623 Isolate* isolate = masm->isolate(); 4624 Label slow, non_function; 4625 4626 // The receiver might implicitly be the global object. This is 4627 // indicated by passing the hole as the receiver to the call 4628 // function stub. 4629 if (ReceiverMightBeImplicit()) { 4630 Label receiver_ok; 4631 // Get the receiver from the stack. 4632 // +1 ~ return address 4633 __ mov(eax, Operand(esp, (argc_ + 1) * kPointerSize)); 4634 // Call as function is indicated with the hole. 4635 __ cmp(eax, isolate->factory()->the_hole_value()); 4636 __ j(not_equal, &receiver_ok, Label::kNear); 4637 // Patch the receiver on the stack with the global receiver object. 4638 __ mov(ecx, GlobalObjectOperand()); 4639 __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); 4640 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), ecx); 4641 __ bind(&receiver_ok); 4642 } 4643 4644 // Check that the function really is a JavaScript function. 4645 __ JumpIfSmi(edi, &non_function); 4646 // Goto slow case if we do not have a function. 4647 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 4648 __ j(not_equal, &slow); 4649 4650 if (RecordCallTarget()) { 4651 GenerateRecordCallTarget(masm); 4652 } 4653 4654 // Fast-case: Just invoke the function. 4655 ParameterCount actual(argc_); 4656 4657 if (ReceiverMightBeImplicit()) { 4658 Label call_as_function; 4659 __ cmp(eax, isolate->factory()->the_hole_value()); 4660 __ j(equal, &call_as_function); 4661 __ InvokeFunction(edi, 4662 actual, 4663 JUMP_FUNCTION, 4664 NullCallWrapper(), 4665 CALL_AS_METHOD); 4666 __ bind(&call_as_function); 4667 } 4668 __ InvokeFunction(edi, 4669 actual, 4670 JUMP_FUNCTION, 4671 NullCallWrapper(), 4672 CALL_AS_FUNCTION); 4673 4674 // Slow-case: Non-function called. 4675 __ bind(&slow); 4676 if (RecordCallTarget()) { 4677 // If there is a call target cache, mark it megamorphic in the 4678 // non-function case. MegamorphicSentinel is an immortal immovable 4679 // object (undefined) so no write barrier is needed. 4680 __ mov(FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset), 4681 Immediate(TypeFeedbackCells::MegamorphicSentinel(isolate))); 4682 } 4683 // Check for function proxy. 4684 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); 4685 __ j(not_equal, &non_function); 4686 __ pop(ecx); 4687 __ push(edi); // put proxy as additional argument under return address 4688 __ push(ecx); 4689 __ Set(eax, Immediate(argc_ + 1)); 4690 __ Set(ebx, Immediate(0)); 4691 __ SetCallKind(ecx, CALL_AS_FUNCTION); 4692 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY); 4693 { 4694 Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline(); 4695 __ jmp(adaptor, RelocInfo::CODE_TARGET); 4696 } 4697 4698 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead 4699 // of the original receiver from the call site). 4700 __ bind(&non_function); 4701 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi); 4702 __ Set(eax, Immediate(argc_)); 4703 __ Set(ebx, Immediate(0)); 4704 __ SetCallKind(ecx, CALL_AS_METHOD); 4705 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); 4706 Handle<Code> adaptor = isolate->builtins()->ArgumentsAdaptorTrampoline(); 4707 __ jmp(adaptor, RelocInfo::CODE_TARGET); 4708 } 4709 4710 4711 void CallConstructStub::Generate(MacroAssembler* masm) { 4712 // eax : number of arguments 4713 // ebx : cache cell for call target 4714 // edi : constructor function 4715 Label slow, non_function_call; 4716 4717 // Check that function is not a smi. 4718 __ JumpIfSmi(edi, &non_function_call); 4719 // Check that function is a JSFunction. 4720 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ecx); 4721 __ j(not_equal, &slow); 4722 4723 if (RecordCallTarget()) { 4724 GenerateRecordCallTarget(masm); 4725 } 4726 4727 // Jump to the function-specific construct stub. 4728 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); 4729 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kConstructStubOffset)); 4730 __ lea(ebx, FieldOperand(ebx, Code::kHeaderSize)); 4731 __ jmp(ebx); 4732 4733 // edi: called object 4734 // eax: number of arguments 4735 // ecx: object map 4736 Label do_call; 4737 __ bind(&slow); 4738 __ CmpInstanceType(ecx, JS_FUNCTION_PROXY_TYPE); 4739 __ j(not_equal, &non_function_call); 4740 __ GetBuiltinEntry(edx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR); 4741 __ jmp(&do_call); 4742 4743 __ bind(&non_function_call); 4744 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); 4745 __ bind(&do_call); 4746 // Set expected number of arguments to zero (not changing eax). 4747 __ Set(ebx, Immediate(0)); 4748 Handle<Code> arguments_adaptor = 4749 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); 4750 __ SetCallKind(ecx, CALL_AS_METHOD); 4751 __ jmp(arguments_adaptor, RelocInfo::CODE_TARGET); 4752 } 4753 4754 4755 bool CEntryStub::NeedsImmovableCode() { 4756 return false; 4757 } 4758 4759 4760 bool CEntryStub::IsPregenerated() { 4761 return (!save_doubles_ || ISOLATE->fp_stubs_generated()) && 4762 result_size_ == 1; 4763 } 4764 4765 4766 void CodeStub::GenerateStubsAheadOfTime() { 4767 CEntryStub::GenerateAheadOfTime(); 4768 StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(); 4769 // It is important that the store buffer overflow stubs are generated first. 4770 RecordWriteStub::GenerateFixedRegStubsAheadOfTime(); 4771 } 4772 4773 4774 void CodeStub::GenerateFPStubs() { 4775 CEntryStub save_doubles(1, kSaveFPRegs); 4776 Handle<Code> code = save_doubles.GetCode(); 4777 code->set_is_pregenerated(true); 4778 code->GetIsolate()->set_fp_stubs_generated(true); 4779 } 4780 4781 4782 void CEntryStub::GenerateAheadOfTime() { 4783 CEntryStub stub(1, kDontSaveFPRegs); 4784 Handle<Code> code = stub.GetCode(); 4785 code->set_is_pregenerated(true); 4786 } 4787 4788 4789 void CEntryStub::GenerateCore(MacroAssembler* masm, 4790 Label* throw_normal_exception, 4791 Label* throw_termination_exception, 4792 Label* throw_out_of_memory_exception, 4793 bool do_gc, 4794 bool always_allocate_scope) { 4795 // eax: result parameter for PerformGC, if any 4796 // ebx: pointer to C function (C callee-saved) 4797 // ebp: frame pointer (restored after C call) 4798 // esp: stack pointer (restored after C call) 4799 // edi: number of arguments including receiver (C callee-saved) 4800 // esi: pointer to the first argument (C callee-saved) 4801 4802 // Result returned in eax, or eax+edx if result_size_ is 2. 4803 4804 // Check stack alignment. 4805 if (FLAG_debug_code) { 4806 __ CheckStackAlignment(); 4807 } 4808 4809 if (do_gc) { 4810 // Pass failure code returned from last attempt as first argument to 4811 // PerformGC. No need to use PrepareCallCFunction/CallCFunction here as the 4812 // stack alignment is known to be correct. This function takes one argument 4813 // which is passed on the stack, and we know that the stack has been 4814 // prepared to pass at least one argument. 4815 __ mov(Operand(esp, 0 * kPointerSize), eax); // Result. 4816 __ call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY); 4817 } 4818 4819 ExternalReference scope_depth = 4820 ExternalReference::heap_always_allocate_scope_depth(masm->isolate()); 4821 if (always_allocate_scope) { 4822 __ inc(Operand::StaticVariable(scope_depth)); 4823 } 4824 4825 // Call C function. 4826 __ mov(Operand(esp, 0 * kPointerSize), edi); // argc. 4827 __ mov(Operand(esp, 1 * kPointerSize), esi); // argv. 4828 __ mov(Operand(esp, 2 * kPointerSize), 4829 Immediate(ExternalReference::isolate_address())); 4830 __ call(ebx); 4831 // Result is in eax or edx:eax - do not destroy these registers! 4832 4833 if (always_allocate_scope) { 4834 __ dec(Operand::StaticVariable(scope_depth)); 4835 } 4836 4837 // Make sure we're not trying to return 'the hole' from the runtime 4838 // call as this may lead to crashes in the IC code later. 4839 if (FLAG_debug_code) { 4840 Label okay; 4841 __ cmp(eax, masm->isolate()->factory()->the_hole_value()); 4842 __ j(not_equal, &okay, Label::kNear); 4843 __ int3(); 4844 __ bind(&okay); 4845 } 4846 4847 // Check for failure result. 4848 Label failure_returned; 4849 STATIC_ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0); 4850 __ lea(ecx, Operand(eax, 1)); 4851 // Lower 2 bits of ecx are 0 iff eax has failure tag. 4852 __ test(ecx, Immediate(kFailureTagMask)); 4853 __ j(zero, &failure_returned); 4854 4855 ExternalReference pending_exception_address( 4856 Isolate::kPendingExceptionAddress, masm->isolate()); 4857 4858 // Check that there is no pending exception, otherwise we 4859 // should have returned some failure value. 4860 if (FLAG_debug_code) { 4861 __ push(edx); 4862 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value())); 4863 Label okay; 4864 __ cmp(edx, Operand::StaticVariable(pending_exception_address)); 4865 // Cannot use check here as it attempts to generate call into runtime. 4866 __ j(equal, &okay, Label::kNear); 4867 __ int3(); 4868 __ bind(&okay); 4869 __ pop(edx); 4870 } 4871 4872 // Exit the JavaScript to C++ exit frame. 4873 __ LeaveExitFrame(save_doubles_ == kSaveFPRegs); 4874 __ ret(0); 4875 4876 // Handling of failure. 4877 __ bind(&failure_returned); 4878 4879 Label retry; 4880 // If the returned exception is RETRY_AFTER_GC continue at retry label 4881 STATIC_ASSERT(Failure::RETRY_AFTER_GC == 0); 4882 __ test(eax, Immediate(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize)); 4883 __ j(zero, &retry, Label::kNear); 4884 4885 // Special handling of out of memory exceptions. 4886 __ cmp(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException())); 4887 __ j(equal, throw_out_of_memory_exception); 4888 4889 // Retrieve the pending exception and clear the variable. 4890 __ mov(eax, Operand::StaticVariable(pending_exception_address)); 4891 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value())); 4892 __ mov(Operand::StaticVariable(pending_exception_address), edx); 4893 4894 // Special handling of termination exceptions which are uncatchable 4895 // by javascript code. 4896 __ cmp(eax, masm->isolate()->factory()->termination_exception()); 4897 __ j(equal, throw_termination_exception); 4898 4899 // Handle normal exception. 4900 __ jmp(throw_normal_exception); 4901 4902 // Retry. 4903 __ bind(&retry); 4904 } 4905 4906 4907 void CEntryStub::Generate(MacroAssembler* masm) { 4908 // eax: number of arguments including receiver 4909 // ebx: pointer to C function (C callee-saved) 4910 // ebp: frame pointer (restored after C call) 4911 // esp: stack pointer (restored after C call) 4912 // esi: current context (C callee-saved) 4913 // edi: JS function of the caller (C callee-saved) 4914 4915 // NOTE: Invocations of builtins may return failure objects instead 4916 // of a proper result. The builtin entry handles this by performing 4917 // a garbage collection and retrying the builtin (twice). 4918 4919 // Enter the exit frame that transitions from JavaScript to C++. 4920 __ EnterExitFrame(save_doubles_ == kSaveFPRegs); 4921 4922 // eax: result parameter for PerformGC, if any (setup below) 4923 // ebx: pointer to builtin function (C callee-saved) 4924 // ebp: frame pointer (restored after C call) 4925 // esp: stack pointer (restored after C call) 4926 // edi: number of arguments including receiver (C callee-saved) 4927 // esi: argv pointer (C callee-saved) 4928 4929 Label throw_normal_exception; 4930 Label throw_termination_exception; 4931 Label throw_out_of_memory_exception; 4932 4933 // Call into the runtime system. 4934 GenerateCore(masm, 4935 &throw_normal_exception, 4936 &throw_termination_exception, 4937 &throw_out_of_memory_exception, 4938 false, 4939 false); 4940 4941 // Do space-specific GC and retry runtime call. 4942 GenerateCore(masm, 4943 &throw_normal_exception, 4944 &throw_termination_exception, 4945 &throw_out_of_memory_exception, 4946 true, 4947 false); 4948 4949 // Do full GC and retry runtime call one final time. 4950 Failure* failure = Failure::InternalError(); 4951 __ mov(eax, Immediate(reinterpret_cast<int32_t>(failure))); 4952 GenerateCore(masm, 4953 &throw_normal_exception, 4954 &throw_termination_exception, 4955 &throw_out_of_memory_exception, 4956 true, 4957 true); 4958 4959 __ bind(&throw_out_of_memory_exception); 4960 // Set external caught exception to false. 4961 Isolate* isolate = masm->isolate(); 4962 ExternalReference external_caught(Isolate::kExternalCaughtExceptionAddress, 4963 isolate); 4964 __ mov(Operand::StaticVariable(external_caught), Immediate(false)); 4965 4966 // Set pending exception and eax to out of memory exception. 4967 ExternalReference pending_exception(Isolate::kPendingExceptionAddress, 4968 isolate); 4969 __ mov(eax, reinterpret_cast<int32_t>(Failure::OutOfMemoryException())); 4970 __ mov(Operand::StaticVariable(pending_exception), eax); 4971 // Fall through to the next label. 4972 4973 __ bind(&throw_termination_exception); 4974 __ ThrowUncatchable(eax); 4975 4976 __ bind(&throw_normal_exception); 4977 __ Throw(eax); 4978 } 4979 4980 4981 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { 4982 Label invoke, handler_entry, exit; 4983 Label not_outermost_js, not_outermost_js_2; 4984 4985 // Set up frame. 4986 __ push(ebp); 4987 __ mov(ebp, esp); 4988 4989 // Push marker in two places. 4990 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; 4991 __ push(Immediate(Smi::FromInt(marker))); // context slot 4992 __ push(Immediate(Smi::FromInt(marker))); // function slot 4993 // Save callee-saved registers (C calling conventions). 4994 __ push(edi); 4995 __ push(esi); 4996 __ push(ebx); 4997 4998 // Save copies of the top frame descriptor on the stack. 4999 ExternalReference c_entry_fp(Isolate::kCEntryFPAddress, masm->isolate()); 5000 __ push(Operand::StaticVariable(c_entry_fp)); 5001 5002 // If this is the outermost JS call, set js_entry_sp value. 5003 ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, 5004 masm->isolate()); 5005 __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0)); 5006 __ j(not_equal, ¬_outermost_js, Label::kNear); 5007 __ mov(Operand::StaticVariable(js_entry_sp), ebp); 5008 __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); 5009 Label cont; 5010 __ jmp(&cont, Label::kNear); 5011 __ bind(¬_outermost_js); 5012 __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME))); 5013 __ bind(&cont); 5014 5015 // Jump to a faked try block that does the invoke, with a faked catch 5016 // block that sets the pending exception. 5017 __ jmp(&invoke); 5018 __ bind(&handler_entry); 5019 handler_offset_ = handler_entry.pos(); 5020 // Caught exception: Store result (exception) in the pending exception 5021 // field in the JSEnv and return a failure sentinel. 5022 ExternalReference pending_exception(Isolate::kPendingExceptionAddress, 5023 masm->isolate()); 5024 __ mov(Operand::StaticVariable(pending_exception), eax); 5025 __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception())); 5026 __ jmp(&exit); 5027 5028 // Invoke: Link this frame into the handler chain. There's only one 5029 // handler block in this code object, so its index is 0. 5030 __ bind(&invoke); 5031 __ PushTryHandler(StackHandler::JS_ENTRY, 0); 5032 5033 // Clear any pending exceptions. 5034 __ mov(edx, Immediate(masm->isolate()->factory()->the_hole_value())); 5035 __ mov(Operand::StaticVariable(pending_exception), edx); 5036 5037 // Fake a receiver (NULL). 5038 __ push(Immediate(0)); // receiver 5039 5040 // Invoke the function by calling through JS entry trampoline builtin and 5041 // pop the faked function when we return. Notice that we cannot store a 5042 // reference to the trampoline code directly in this stub, because the 5043 // builtin stubs may not have been generated yet. 5044 if (is_construct) { 5045 ExternalReference construct_entry(Builtins::kJSConstructEntryTrampoline, 5046 masm->isolate()); 5047 __ mov(edx, Immediate(construct_entry)); 5048 } else { 5049 ExternalReference entry(Builtins::kJSEntryTrampoline, 5050 masm->isolate()); 5051 __ mov(edx, Immediate(entry)); 5052 } 5053 __ mov(edx, Operand(edx, 0)); // deref address 5054 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); 5055 __ call(edx); 5056 5057 // Unlink this frame from the handler chain. 5058 __ PopTryHandler(); 5059 5060 __ bind(&exit); 5061 // Check if the current stack frame is marked as the outermost JS frame. 5062 __ pop(ebx); 5063 __ cmp(ebx, Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); 5064 __ j(not_equal, ¬_outermost_js_2); 5065 __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); 5066 __ bind(¬_outermost_js_2); 5067 5068 // Restore the top frame descriptor from the stack. 5069 __ pop(Operand::StaticVariable(ExternalReference( 5070 Isolate::kCEntryFPAddress, 5071 masm->isolate()))); 5072 5073 // Restore callee-saved registers (C calling conventions). 5074 __ pop(ebx); 5075 __ pop(esi); 5076 __ pop(edi); 5077 __ add(esp, Immediate(2 * kPointerSize)); // remove markers 5078 5079 // Restore frame pointer and return. 5080 __ pop(ebp); 5081 __ ret(0); 5082 } 5083 5084 5085 // Generate stub code for instanceof. 5086 // This code can patch a call site inlined cache of the instance of check, 5087 // which looks like this. 5088 // 5089 // 81 ff XX XX XX XX cmp edi, <the hole, patched to a map> 5090 // 75 0a jne <some near label> 5091 // b8 XX XX XX XX mov eax, <the hole, patched to either true or false> 5092 // 5093 // If call site patching is requested the stack will have the delta from the 5094 // return address to the cmp instruction just below the return address. This 5095 // also means that call site patching can only take place with arguments in 5096 // registers. TOS looks like this when call site patching is requested 5097 // 5098 // esp[0] : return address 5099 // esp[4] : delta from return address to cmp instruction 5100 // 5101 void InstanceofStub::Generate(MacroAssembler* masm) { 5102 // Call site inlining and patching implies arguments in registers. 5103 ASSERT(HasArgsInRegisters() || !HasCallSiteInlineCheck()); 5104 5105 // Fixed register usage throughout the stub. 5106 Register object = eax; // Object (lhs). 5107 Register map = ebx; // Map of the object. 5108 Register function = edx; // Function (rhs). 5109 Register prototype = edi; // Prototype of the function. 5110 Register scratch = ecx; 5111 5112 // Constants describing the call site code to patch. 5113 static const int kDeltaToCmpImmediate = 2; 5114 static const int kDeltaToMov = 8; 5115 static const int kDeltaToMovImmediate = 9; 5116 static const int8_t kCmpEdiOperandByte1 = BitCast<int8_t, uint8_t>(0x3b); 5117 static const int8_t kCmpEdiOperandByte2 = BitCast<int8_t, uint8_t>(0x3d); 5118 static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8); 5119 5120 ExternalReference roots_array_start = 5121 ExternalReference::roots_array_start(masm->isolate()); 5122 5123 ASSERT_EQ(object.code(), InstanceofStub::left().code()); 5124 ASSERT_EQ(function.code(), InstanceofStub::right().code()); 5125 5126 // Get the object and function - they are always both needed. 5127 Label slow, not_js_object; 5128 if (!HasArgsInRegisters()) { 5129 __ mov(object, Operand(esp, 2 * kPointerSize)); 5130 __ mov(function, Operand(esp, 1 * kPointerSize)); 5131 } 5132 5133 // Check that the left hand is a JS object. 5134 __ JumpIfSmi(object, ¬_js_object); 5135 __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); 5136 5137 // If there is a call site cache don't look in the global cache, but do the 5138 // real lookup and update the call site cache. 5139 if (!HasCallSiteInlineCheck()) { 5140 // Look up the function and the map in the instanceof cache. 5141 Label miss; 5142 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); 5143 __ cmp(function, Operand::StaticArray(scratch, 5144 times_pointer_size, 5145 roots_array_start)); 5146 __ j(not_equal, &miss, Label::kNear); 5147 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); 5148 __ cmp(map, Operand::StaticArray( 5149 scratch, times_pointer_size, roots_array_start)); 5150 __ j(not_equal, &miss, Label::kNear); 5151 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 5152 __ mov(eax, Operand::StaticArray( 5153 scratch, times_pointer_size, roots_array_start)); 5154 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 5155 __ bind(&miss); 5156 } 5157 5158 // Get the prototype of the function. 5159 __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true); 5160 5161 // Check that the function prototype is a JS object. 5162 __ JumpIfSmi(prototype, &slow); 5163 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); 5164 5165 // Update the global instanceof or call site inlined cache with the current 5166 // map and function. The cached answer will be set when it is known below. 5167 if (!HasCallSiteInlineCheck()) { 5168 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); 5169 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start), 5170 map); 5171 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); 5172 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start), 5173 function); 5174 } else { 5175 // The constants for the code patching are based on no push instructions 5176 // at the call site. 5177 ASSERT(HasArgsInRegisters()); 5178 // Get return address and delta to inlined map check. 5179 __ mov(scratch, Operand(esp, 0 * kPointerSize)); 5180 __ sub(scratch, Operand(esp, 1 * kPointerSize)); 5181 if (FLAG_debug_code) { 5182 __ cmpb(Operand(scratch, 0), kCmpEdiOperandByte1); 5183 __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 1)"); 5184 __ cmpb(Operand(scratch, 1), kCmpEdiOperandByte2); 5185 __ Assert(equal, "InstanceofStub unexpected call site cache (cmp 2)"); 5186 } 5187 __ mov(scratch, Operand(scratch, kDeltaToCmpImmediate)); 5188 __ mov(Operand(scratch, 0), map); 5189 } 5190 5191 // Loop through the prototype chain of the object looking for the function 5192 // prototype. 5193 __ mov(scratch, FieldOperand(map, Map::kPrototypeOffset)); 5194 Label loop, is_instance, is_not_instance; 5195 __ bind(&loop); 5196 __ cmp(scratch, prototype); 5197 __ j(equal, &is_instance, Label::kNear); 5198 Factory* factory = masm->isolate()->factory(); 5199 __ cmp(scratch, Immediate(factory->null_value())); 5200 __ j(equal, &is_not_instance, Label::kNear); 5201 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); 5202 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); 5203 __ jmp(&loop); 5204 5205 __ bind(&is_instance); 5206 if (!HasCallSiteInlineCheck()) { 5207 __ Set(eax, Immediate(0)); 5208 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 5209 __ mov(Operand::StaticArray(scratch, 5210 times_pointer_size, roots_array_start), eax); 5211 } else { 5212 // Get return address and delta to inlined map check. 5213 __ mov(eax, factory->true_value()); 5214 __ mov(scratch, Operand(esp, 0 * kPointerSize)); 5215 __ sub(scratch, Operand(esp, 1 * kPointerSize)); 5216 if (FLAG_debug_code) { 5217 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); 5218 __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); 5219 } 5220 __ mov(Operand(scratch, kDeltaToMovImmediate), eax); 5221 if (!ReturnTrueFalseObject()) { 5222 __ Set(eax, Immediate(0)); 5223 } 5224 } 5225 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 5226 5227 __ bind(&is_not_instance); 5228 if (!HasCallSiteInlineCheck()) { 5229 __ Set(eax, Immediate(Smi::FromInt(1))); 5230 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); 5231 __ mov(Operand::StaticArray( 5232 scratch, times_pointer_size, roots_array_start), eax); 5233 } else { 5234 // Get return address and delta to inlined map check. 5235 __ mov(eax, factory->false_value()); 5236 __ mov(scratch, Operand(esp, 0 * kPointerSize)); 5237 __ sub(scratch, Operand(esp, 1 * kPointerSize)); 5238 if (FLAG_debug_code) { 5239 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); 5240 __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); 5241 } 5242 __ mov(Operand(scratch, kDeltaToMovImmediate), eax); 5243 if (!ReturnTrueFalseObject()) { 5244 __ Set(eax, Immediate(Smi::FromInt(1))); 5245 } 5246 } 5247 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 5248 5249 Label object_not_null, object_not_null_or_smi; 5250 __ bind(¬_js_object); 5251 // Before null, smi and string value checks, check that the rhs is a function 5252 // as for a non-function rhs an exception needs to be thrown. 5253 __ JumpIfSmi(function, &slow, Label::kNear); 5254 __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch); 5255 __ j(not_equal, &slow, Label::kNear); 5256 5257 // Null is not instance of anything. 5258 __ cmp(object, factory->null_value()); 5259 __ j(not_equal, &object_not_null, Label::kNear); 5260 __ Set(eax, Immediate(Smi::FromInt(1))); 5261 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 5262 5263 __ bind(&object_not_null); 5264 // Smi values is not instance of anything. 5265 __ JumpIfNotSmi(object, &object_not_null_or_smi, Label::kNear); 5266 __ Set(eax, Immediate(Smi::FromInt(1))); 5267 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 5268 5269 __ bind(&object_not_null_or_smi); 5270 // String values is not instance of anything. 5271 Condition is_string = masm->IsObjectStringType(object, scratch, scratch); 5272 __ j(NegateCondition(is_string), &slow, Label::kNear); 5273 __ Set(eax, Immediate(Smi::FromInt(1))); 5274 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 5275 5276 // Slow-case: Go through the JavaScript implementation. 5277 __ bind(&slow); 5278 if (!ReturnTrueFalseObject()) { 5279 // Tail call the builtin which returns 0 or 1. 5280 if (HasArgsInRegisters()) { 5281 // Push arguments below return address. 5282 __ pop(scratch); 5283 __ push(object); 5284 __ push(function); 5285 __ push(scratch); 5286 } 5287 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 5288 } else { 5289 // Call the builtin and convert 0/1 to true/false. 5290 { 5291 FrameScope scope(masm, StackFrame::INTERNAL); 5292 __ push(object); 5293 __ push(function); 5294 __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION); 5295 } 5296 Label true_value, done; 5297 __ test(eax, eax); 5298 __ j(zero, &true_value, Label::kNear); 5299 __ mov(eax, factory->false_value()); 5300 __ jmp(&done, Label::kNear); 5301 __ bind(&true_value); 5302 __ mov(eax, factory->true_value()); 5303 __ bind(&done); 5304 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); 5305 } 5306 } 5307 5308 5309 Register InstanceofStub::left() { return eax; } 5310 5311 5312 Register InstanceofStub::right() { return edx; } 5313 5314 5315 int CompareStub::MinorKey() { 5316 // Encode the three parameters in a unique 16 bit value. To avoid duplicate 5317 // stubs the never NaN NaN condition is only taken into account if the 5318 // condition is equals. 5319 ASSERT(static_cast<unsigned>(cc_) < (1 << 12)); 5320 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 5321 return ConditionField::encode(static_cast<unsigned>(cc_)) 5322 | RegisterField::encode(false) // lhs_ and rhs_ are not used 5323 | StrictField::encode(strict_) 5324 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) 5325 | IncludeNumberCompareField::encode(include_number_compare_) 5326 | IncludeSmiCompareField::encode(include_smi_compare_); 5327 } 5328 5329 5330 // Unfortunately you have to run without snapshots to see most of these 5331 // names in the profile since most compare stubs end up in the snapshot. 5332 void CompareStub::PrintName(StringStream* stream) { 5333 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); 5334 const char* cc_name; 5335 switch (cc_) { 5336 case less: cc_name = "LT"; break; 5337 case greater: cc_name = "GT"; break; 5338 case less_equal: cc_name = "LE"; break; 5339 case greater_equal: cc_name = "GE"; break; 5340 case equal: cc_name = "EQ"; break; 5341 case not_equal: cc_name = "NE"; break; 5342 default: cc_name = "UnknownCondition"; break; 5343 } 5344 bool is_equality = cc_ == equal || cc_ == not_equal; 5345 stream->Add("CompareStub_%s", cc_name); 5346 if (strict_ && is_equality) stream->Add("_STRICT"); 5347 if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); 5348 if (!include_number_compare_) stream->Add("_NO_NUMBER"); 5349 if (!include_smi_compare_) stream->Add("_NO_SMI"); 5350 } 5351 5352 5353 // ------------------------------------------------------------------------- 5354 // StringCharCodeAtGenerator 5355 5356 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { 5357 // If the receiver is a smi trigger the non-string case. 5358 STATIC_ASSERT(kSmiTag == 0); 5359 __ JumpIfSmi(object_, receiver_not_string_); 5360 5361 // Fetch the instance type of the receiver into result register. 5362 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); 5363 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 5364 // If the receiver is not a string trigger the non-string case. 5365 __ test(result_, Immediate(kIsNotStringMask)); 5366 __ j(not_zero, receiver_not_string_); 5367 5368 // If the index is non-smi trigger the non-smi case. 5369 STATIC_ASSERT(kSmiTag == 0); 5370 __ JumpIfNotSmi(index_, &index_not_smi_); 5371 __ bind(&got_smi_index_); 5372 5373 // Check for index out of range. 5374 __ cmp(index_, FieldOperand(object_, String::kLengthOffset)); 5375 __ j(above_equal, index_out_of_range_); 5376 5377 __ SmiUntag(index_); 5378 5379 Factory* factory = masm->isolate()->factory(); 5380 StringCharLoadGenerator::Generate( 5381 masm, factory, object_, index_, result_, &call_runtime_); 5382 5383 __ SmiTag(result_); 5384 __ bind(&exit_); 5385 } 5386 5387 5388 void StringCharCodeAtGenerator::GenerateSlow( 5389 MacroAssembler* masm, 5390 const RuntimeCallHelper& call_helper) { 5391 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); 5392 5393 // Index is not a smi. 5394 __ bind(&index_not_smi_); 5395 // If index is a heap number, try converting it to an integer. 5396 __ CheckMap(index_, 5397 masm->isolate()->factory()->heap_number_map(), 5398 index_not_number_, 5399 DONT_DO_SMI_CHECK); 5400 call_helper.BeforeCall(masm); 5401 __ push(object_); 5402 __ push(index_); // Consumed by runtime conversion function. 5403 if (index_flags_ == STRING_INDEX_IS_NUMBER) { 5404 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); 5405 } else { 5406 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); 5407 // NumberToSmi discards numbers that are not exact integers. 5408 __ CallRuntime(Runtime::kNumberToSmi, 1); 5409 } 5410 if (!index_.is(eax)) { 5411 // Save the conversion result before the pop instructions below 5412 // have a chance to overwrite it. 5413 __ mov(index_, eax); 5414 } 5415 __ pop(object_); 5416 // Reload the instance type. 5417 __ mov(result_, FieldOperand(object_, HeapObject::kMapOffset)); 5418 __ movzx_b(result_, FieldOperand(result_, Map::kInstanceTypeOffset)); 5419 call_helper.AfterCall(masm); 5420 // If index is still not a smi, it must be out of range. 5421 STATIC_ASSERT(kSmiTag == 0); 5422 __ JumpIfNotSmi(index_, index_out_of_range_); 5423 // Otherwise, return to the fast path. 5424 __ jmp(&got_smi_index_); 5425 5426 // Call runtime. We get here when the receiver is a string and the 5427 // index is a number, but the code of getting the actual character 5428 // is too complex (e.g., when the string needs to be flattened). 5429 __ bind(&call_runtime_); 5430 call_helper.BeforeCall(masm); 5431 __ push(object_); 5432 __ SmiTag(index_); 5433 __ push(index_); 5434 __ CallRuntime(Runtime::kStringCharCodeAt, 2); 5435 if (!result_.is(eax)) { 5436 __ mov(result_, eax); 5437 } 5438 call_helper.AfterCall(masm); 5439 __ jmp(&exit_); 5440 5441 __ Abort("Unexpected fallthrough from CharCodeAt slow case"); 5442 } 5443 5444 5445 // ------------------------------------------------------------------------- 5446 // StringCharFromCodeGenerator 5447 5448 void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) { 5449 // Fast case of Heap::LookupSingleCharacterStringFromCode. 5450 STATIC_ASSERT(kSmiTag == 0); 5451 STATIC_ASSERT(kSmiShiftSize == 0); 5452 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); 5453 __ test(code_, 5454 Immediate(kSmiTagMask | 5455 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); 5456 __ j(not_zero, &slow_case_); 5457 5458 Factory* factory = masm->isolate()->factory(); 5459 __ Set(result_, Immediate(factory->single_character_string_cache())); 5460 STATIC_ASSERT(kSmiTag == 0); 5461 STATIC_ASSERT(kSmiTagSize == 1); 5462 STATIC_ASSERT(kSmiShiftSize == 0); 5463 // At this point code register contains smi tagged ASCII char code. 5464 __ mov(result_, FieldOperand(result_, 5465 code_, times_half_pointer_size, 5466 FixedArray::kHeaderSize)); 5467 __ cmp(result_, factory->undefined_value()); 5468 __ j(equal, &slow_case_); 5469 __ bind(&exit_); 5470 } 5471 5472 5473 void StringCharFromCodeGenerator::GenerateSlow( 5474 MacroAssembler* masm, 5475 const RuntimeCallHelper& call_helper) { 5476 __ Abort("Unexpected fallthrough to CharFromCode slow case"); 5477 5478 __ bind(&slow_case_); 5479 call_helper.BeforeCall(masm); 5480 __ push(code_); 5481 __ CallRuntime(Runtime::kCharFromCode, 1); 5482 if (!result_.is(eax)) { 5483 __ mov(result_, eax); 5484 } 5485 call_helper.AfterCall(masm); 5486 __ jmp(&exit_); 5487 5488 __ Abort("Unexpected fallthrough from CharFromCode slow case"); 5489 } 5490 5491 5492 // ------------------------------------------------------------------------- 5493 // StringCharAtGenerator 5494 5495 void StringCharAtGenerator::GenerateFast(MacroAssembler* masm) { 5496 char_code_at_generator_.GenerateFast(masm); 5497 char_from_code_generator_.GenerateFast(masm); 5498 } 5499 5500 5501 void StringCharAtGenerator::GenerateSlow( 5502 MacroAssembler* masm, 5503 const RuntimeCallHelper& call_helper) { 5504 char_code_at_generator_.GenerateSlow(masm, call_helper); 5505 char_from_code_generator_.GenerateSlow(masm, call_helper); 5506 } 5507 5508 5509 void StringAddStub::Generate(MacroAssembler* masm) { 5510 Label call_runtime, call_builtin; 5511 Builtins::JavaScript builtin_id = Builtins::ADD; 5512 5513 // Load the two arguments. 5514 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. 5515 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. 5516 5517 // Make sure that both arguments are strings if not known in advance. 5518 if (flags_ == NO_STRING_ADD_FLAGS) { 5519 __ JumpIfSmi(eax, &call_runtime); 5520 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); 5521 __ j(above_equal, &call_runtime); 5522 5523 // First argument is a a string, test second. 5524 __ JumpIfSmi(edx, &call_runtime); 5525 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); 5526 __ j(above_equal, &call_runtime); 5527 } else { 5528 // Here at least one of the arguments is definitely a string. 5529 // We convert the one that is not known to be a string. 5530 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { 5531 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); 5532 GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi, 5533 &call_builtin); 5534 builtin_id = Builtins::STRING_ADD_RIGHT; 5535 } else if ((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) == 0) { 5536 ASSERT((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) != 0); 5537 GenerateConvertArgument(masm, 1 * kPointerSize, edx, ebx, ecx, edi, 5538 &call_builtin); 5539 builtin_id = Builtins::STRING_ADD_LEFT; 5540 } 5541 } 5542 5543 // Both arguments are strings. 5544 // eax: first string 5545 // edx: second string 5546 // Check if either of the strings are empty. In that case return the other. 5547 Label second_not_zero_length, both_not_zero_length; 5548 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); 5549 STATIC_ASSERT(kSmiTag == 0); 5550 __ test(ecx, ecx); 5551 __ j(not_zero, &second_not_zero_length, Label::kNear); 5552 // Second string is empty, result is first string which is already in eax. 5553 Counters* counters = masm->isolate()->counters(); 5554 __ IncrementCounter(counters->string_add_native(), 1); 5555 __ ret(2 * kPointerSize); 5556 __ bind(&second_not_zero_length); 5557 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); 5558 STATIC_ASSERT(kSmiTag == 0); 5559 __ test(ebx, ebx); 5560 __ j(not_zero, &both_not_zero_length, Label::kNear); 5561 // First string is empty, result is second string which is in edx. 5562 __ mov(eax, edx); 5563 __ IncrementCounter(counters->string_add_native(), 1); 5564 __ ret(2 * kPointerSize); 5565 5566 // Both strings are non-empty. 5567 // eax: first string 5568 // ebx: length of first string as a smi 5569 // ecx: length of second string as a smi 5570 // edx: second string 5571 // Look at the length of the result of adding the two strings. 5572 Label string_add_flat_result, longer_than_two; 5573 __ bind(&both_not_zero_length); 5574 __ add(ebx, ecx); 5575 STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); 5576 // Handle exceptionally long strings in the runtime system. 5577 __ j(overflow, &call_runtime); 5578 // Use the symbol table when adding two one character strings, as it 5579 // helps later optimizations to return a symbol here. 5580 __ cmp(ebx, Immediate(Smi::FromInt(2))); 5581 __ j(not_equal, &longer_than_two); 5582 5583 // Check that both strings are non-external ASCII strings. 5584 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, &call_runtime); 5585 5586 // Get the two characters forming the new string. 5587 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); 5588 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); 5589 5590 // Try to lookup two character string in symbol table. If it is not found 5591 // just allocate a new one. 5592 Label make_two_character_string, make_two_character_string_no_reload; 5593 StringHelper::GenerateTwoCharacterSymbolTableProbe( 5594 masm, ebx, ecx, eax, edx, edi, 5595 &make_two_character_string_no_reload, &make_two_character_string); 5596 __ IncrementCounter(counters->string_add_native(), 1); 5597 __ ret(2 * kPointerSize); 5598 5599 // Allocate a two character string. 5600 __ bind(&make_two_character_string); 5601 // Reload the arguments. 5602 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. 5603 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. 5604 // Get the two characters forming the new string. 5605 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); 5606 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); 5607 __ bind(&make_two_character_string_no_reload); 5608 __ IncrementCounter(counters->string_add_make_two_char(), 1); 5609 __ AllocateAsciiString(eax, 2, edi, edx, &call_runtime); 5610 // Pack both characters in ebx. 5611 __ shl(ecx, kBitsPerByte); 5612 __ or_(ebx, ecx); 5613 // Set the characters in the new string. 5614 __ mov_w(FieldOperand(eax, SeqAsciiString::kHeaderSize), ebx); 5615 __ IncrementCounter(counters->string_add_native(), 1); 5616 __ ret(2 * kPointerSize); 5617 5618 __ bind(&longer_than_two); 5619 // Check if resulting string will be flat. 5620 __ cmp(ebx, Immediate(Smi::FromInt(ConsString::kMinLength))); 5621 __ j(below, &string_add_flat_result); 5622 5623 // If result is not supposed to be flat allocate a cons string object. If both 5624 // strings are ASCII the result is an ASCII cons string. 5625 Label non_ascii, allocated, ascii_data; 5626 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); 5627 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); 5628 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 5629 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); 5630 __ and_(ecx, edi); 5631 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 5632 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 5633 __ test(ecx, Immediate(kStringEncodingMask)); 5634 __ j(zero, &non_ascii); 5635 __ bind(&ascii_data); 5636 // Allocate an ASCII cons string. 5637 __ AllocateAsciiConsString(ecx, edi, no_reg, &call_runtime); 5638 __ bind(&allocated); 5639 // Fill the fields of the cons string. 5640 if (FLAG_debug_code) __ AbortIfNotSmi(ebx); 5641 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); 5642 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), 5643 Immediate(String::kEmptyHashField)); 5644 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); 5645 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); 5646 __ mov(eax, ecx); 5647 __ IncrementCounter(counters->string_add_native(), 1); 5648 __ ret(2 * kPointerSize); 5649 __ bind(&non_ascii); 5650 // At least one of the strings is two-byte. Check whether it happens 5651 // to contain only ASCII characters. 5652 // ecx: first instance type AND second instance type. 5653 // edi: second instance type. 5654 __ test(ecx, Immediate(kAsciiDataHintMask)); 5655 __ j(not_zero, &ascii_data); 5656 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 5657 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 5658 __ xor_(edi, ecx); 5659 STATIC_ASSERT(kAsciiStringTag != 0 && kAsciiDataHintTag != 0); 5660 __ and_(edi, kAsciiStringTag | kAsciiDataHintTag); 5661 __ cmp(edi, kAsciiStringTag | kAsciiDataHintTag); 5662 __ j(equal, &ascii_data); 5663 // Allocate a two byte cons string. 5664 __ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime); 5665 __ jmp(&allocated); 5666 5667 // We cannot encounter sliced strings or cons strings here since: 5668 STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); 5669 // Handle creating a flat result from either external or sequential strings. 5670 // Locate the first characters' locations. 5671 // eax: first string 5672 // ebx: length of resulting flat string as a smi 5673 // edx: second string 5674 Label first_prepared, second_prepared; 5675 Label first_is_sequential, second_is_sequential; 5676 __ bind(&string_add_flat_result); 5677 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 5678 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 5679 // ecx: instance type of first string 5680 STATIC_ASSERT(kSeqStringTag == 0); 5681 __ test_b(ecx, kStringRepresentationMask); 5682 __ j(zero, &first_is_sequential, Label::kNear); 5683 // Rule out short external string and load string resource. 5684 STATIC_ASSERT(kShortExternalStringTag != 0); 5685 __ test_b(ecx, kShortExternalStringMask); 5686 __ j(not_zero, &call_runtime); 5687 __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); 5688 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); 5689 __ jmp(&first_prepared, Label::kNear); 5690 __ bind(&first_is_sequential); 5691 __ add(eax, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 5692 __ bind(&first_prepared); 5693 5694 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); 5695 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); 5696 // Check whether both strings have same encoding. 5697 // edi: instance type of second string 5698 __ xor_(ecx, edi); 5699 __ test_b(ecx, kStringEncodingMask); 5700 __ j(not_zero, &call_runtime); 5701 STATIC_ASSERT(kSeqStringTag == 0); 5702 __ test_b(edi, kStringRepresentationMask); 5703 __ j(zero, &second_is_sequential, Label::kNear); 5704 // Rule out short external string and load string resource. 5705 STATIC_ASSERT(kShortExternalStringTag != 0); 5706 __ test_b(edi, kShortExternalStringMask); 5707 __ j(not_zero, &call_runtime); 5708 __ mov(edx, FieldOperand(edx, ExternalString::kResourceDataOffset)); 5709 STATIC_ASSERT(SeqAsciiString::kHeaderSize == SeqTwoByteString::kHeaderSize); 5710 __ jmp(&second_prepared, Label::kNear); 5711 __ bind(&second_is_sequential); 5712 __ add(edx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 5713 __ bind(&second_prepared); 5714 5715 // Push the addresses of both strings' first characters onto the stack. 5716 __ push(edx); 5717 __ push(eax); 5718 5719 Label non_ascii_string_add_flat_result, call_runtime_drop_two; 5720 // edi: instance type of second string 5721 // First string and second string have the same encoding. 5722 STATIC_ASSERT(kTwoByteStringTag == 0); 5723 __ test_b(edi, kStringEncodingMask); 5724 __ j(zero, &non_ascii_string_add_flat_result); 5725 5726 // Both strings are ASCII strings. 5727 // ebx: length of resulting flat string as a smi 5728 __ SmiUntag(ebx); 5729 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); 5730 // eax: result string 5731 __ mov(ecx, eax); 5732 // Locate first character of result. 5733 __ add(ecx, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 5734 // Load first argument's length and first character location. Account for 5735 // values currently on the stack when fetching arguments from it. 5736 __ mov(edx, Operand(esp, 4 * kPointerSize)); 5737 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 5738 __ SmiUntag(edi); 5739 __ pop(edx); 5740 // eax: result string 5741 // ecx: first character of result 5742 // edx: first char of first argument 5743 // edi: length of first argument 5744 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); 5745 // Load second argument's length and first character location. Account for 5746 // values currently on the stack when fetching arguments from it. 5747 __ mov(edx, Operand(esp, 2 * kPointerSize)); 5748 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 5749 __ SmiUntag(edi); 5750 __ pop(edx); 5751 // eax: result string 5752 // ecx: next character of result 5753 // edx: first char of second argument 5754 // edi: length of second argument 5755 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); 5756 __ IncrementCounter(counters->string_add_native(), 1); 5757 __ ret(2 * kPointerSize); 5758 5759 // Handle creating a flat two byte result. 5760 // eax: first string - known to be two byte 5761 // ebx: length of resulting flat string as a smi 5762 // edx: second string 5763 __ bind(&non_ascii_string_add_flat_result); 5764 // Both strings are two byte strings. 5765 __ SmiUntag(ebx); 5766 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); 5767 // eax: result string 5768 __ mov(ecx, eax); 5769 // Locate first character of result. 5770 __ add(ecx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 5771 // Load second argument's length and first character location. Account for 5772 // values currently on the stack when fetching arguments from it. 5773 __ mov(edx, Operand(esp, 4 * kPointerSize)); 5774 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 5775 __ SmiUntag(edi); 5776 __ pop(edx); 5777 // eax: result string 5778 // ecx: first character of result 5779 // edx: first char of first argument 5780 // edi: length of first argument 5781 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); 5782 // Load second argument's length and first character location. Account for 5783 // values currently on the stack when fetching arguments from it. 5784 __ mov(edx, Operand(esp, 2 * kPointerSize)); 5785 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); 5786 __ SmiUntag(edi); 5787 __ pop(edx); 5788 // eax: result string 5789 // ecx: next character of result 5790 // edx: first char of second argument 5791 // edi: length of second argument 5792 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); 5793 __ IncrementCounter(counters->string_add_native(), 1); 5794 __ ret(2 * kPointerSize); 5795 5796 // Recover stack pointer before jumping to runtime. 5797 __ bind(&call_runtime_drop_two); 5798 __ Drop(2); 5799 // Just jump to runtime to add the two strings. 5800 __ bind(&call_runtime); 5801 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); 5802 5803 if (call_builtin.is_linked()) { 5804 __ bind(&call_builtin); 5805 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); 5806 } 5807 } 5808 5809 5810 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, 5811 int stack_offset, 5812 Register arg, 5813 Register scratch1, 5814 Register scratch2, 5815 Register scratch3, 5816 Label* slow) { 5817 // First check if the argument is already a string. 5818 Label not_string, done; 5819 __ JumpIfSmi(arg, ¬_string); 5820 __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); 5821 __ j(below, &done); 5822 5823 // Check the number to string cache. 5824 Label not_cached; 5825 __ bind(¬_string); 5826 // Puts the cached result into scratch1. 5827 NumberToStringStub::GenerateLookupNumberStringCache(masm, 5828 arg, 5829 scratch1, 5830 scratch2, 5831 scratch3, 5832 false, 5833 ¬_cached); 5834 __ mov(arg, scratch1); 5835 __ mov(Operand(esp, stack_offset), arg); 5836 __ jmp(&done); 5837 5838 // Check if the argument is a safe string wrapper. 5839 __ bind(¬_cached); 5840 __ JumpIfSmi(arg, slow); 5841 __ CmpObjectType(arg, JS_VALUE_TYPE, scratch1); // map -> scratch1. 5842 __ j(not_equal, slow); 5843 __ test_b(FieldOperand(scratch1, Map::kBitField2Offset), 5844 1 << Map::kStringWrapperSafeForDefaultValueOf); 5845 __ j(zero, slow); 5846 __ mov(arg, FieldOperand(arg, JSValue::kValueOffset)); 5847 __ mov(Operand(esp, stack_offset), arg); 5848 5849 __ bind(&done); 5850 } 5851 5852 5853 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, 5854 Register dest, 5855 Register src, 5856 Register count, 5857 Register scratch, 5858 bool ascii) { 5859 Label loop; 5860 __ bind(&loop); 5861 // This loop just copies one character at a time, as it is only used for very 5862 // short strings. 5863 if (ascii) { 5864 __ mov_b(scratch, Operand(src, 0)); 5865 __ mov_b(Operand(dest, 0), scratch); 5866 __ add(src, Immediate(1)); 5867 __ add(dest, Immediate(1)); 5868 } else { 5869 __ mov_w(scratch, Operand(src, 0)); 5870 __ mov_w(Operand(dest, 0), scratch); 5871 __ add(src, Immediate(2)); 5872 __ add(dest, Immediate(2)); 5873 } 5874 __ sub(count, Immediate(1)); 5875 __ j(not_zero, &loop); 5876 } 5877 5878 5879 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, 5880 Register dest, 5881 Register src, 5882 Register count, 5883 Register scratch, 5884 bool ascii) { 5885 // Copy characters using rep movs of doublewords. 5886 // The destination is aligned on a 4 byte boundary because we are 5887 // copying to the beginning of a newly allocated string. 5888 ASSERT(dest.is(edi)); // rep movs destination 5889 ASSERT(src.is(esi)); // rep movs source 5890 ASSERT(count.is(ecx)); // rep movs count 5891 ASSERT(!scratch.is(dest)); 5892 ASSERT(!scratch.is(src)); 5893 ASSERT(!scratch.is(count)); 5894 5895 // Nothing to do for zero characters. 5896 Label done; 5897 __ test(count, count); 5898 __ j(zero, &done); 5899 5900 // Make count the number of bytes to copy. 5901 if (!ascii) { 5902 __ shl(count, 1); 5903 } 5904 5905 // Don't enter the rep movs if there are less than 4 bytes to copy. 5906 Label last_bytes; 5907 __ test(count, Immediate(~3)); 5908 __ j(zero, &last_bytes, Label::kNear); 5909 5910 // Copy from edi to esi using rep movs instruction. 5911 __ mov(scratch, count); 5912 __ sar(count, 2); // Number of doublewords to copy. 5913 __ cld(); 5914 __ rep_movs(); 5915 5916 // Find number of bytes left. 5917 __ mov(count, scratch); 5918 __ and_(count, 3); 5919 5920 // Check if there are more bytes to copy. 5921 __ bind(&last_bytes); 5922 __ test(count, count); 5923 __ j(zero, &done); 5924 5925 // Copy remaining characters. 5926 Label loop; 5927 __ bind(&loop); 5928 __ mov_b(scratch, Operand(src, 0)); 5929 __ mov_b(Operand(dest, 0), scratch); 5930 __ add(src, Immediate(1)); 5931 __ add(dest, Immediate(1)); 5932 __ sub(count, Immediate(1)); 5933 __ j(not_zero, &loop); 5934 5935 __ bind(&done); 5936 } 5937 5938 5939 void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, 5940 Register c1, 5941 Register c2, 5942 Register scratch1, 5943 Register scratch2, 5944 Register scratch3, 5945 Label* not_probed, 5946 Label* not_found) { 5947 // Register scratch3 is the general scratch register in this function. 5948 Register scratch = scratch3; 5949 5950 // Make sure that both characters are not digits as such strings has a 5951 // different hash algorithm. Don't try to look for these in the symbol table. 5952 Label not_array_index; 5953 __ mov(scratch, c1); 5954 __ sub(scratch, Immediate(static_cast<int>('0'))); 5955 __ cmp(scratch, Immediate(static_cast<int>('9' - '0'))); 5956 __ j(above, ¬_array_index, Label::kNear); 5957 __ mov(scratch, c2); 5958 __ sub(scratch, Immediate(static_cast<int>('0'))); 5959 __ cmp(scratch, Immediate(static_cast<int>('9' - '0'))); 5960 __ j(below_equal, not_probed); 5961 5962 __ bind(¬_array_index); 5963 // Calculate the two character string hash. 5964 Register hash = scratch1; 5965 GenerateHashInit(masm, hash, c1, scratch); 5966 GenerateHashAddCharacter(masm, hash, c2, scratch); 5967 GenerateHashGetHash(masm, hash, scratch); 5968 5969 // Collect the two characters in a register. 5970 Register chars = c1; 5971 __ shl(c2, kBitsPerByte); 5972 __ or_(chars, c2); 5973 5974 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 5975 // hash: hash of two character string. 5976 5977 // Load the symbol table. 5978 Register symbol_table = c2; 5979 ExternalReference roots_array_start = 5980 ExternalReference::roots_array_start(masm->isolate()); 5981 __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex)); 5982 __ mov(symbol_table, 5983 Operand::StaticArray(scratch, times_pointer_size, roots_array_start)); 5984 5985 // Calculate capacity mask from the symbol table capacity. 5986 Register mask = scratch2; 5987 __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); 5988 __ SmiUntag(mask); 5989 __ sub(mask, Immediate(1)); 5990 5991 // Registers 5992 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. 5993 // hash: hash of two character string 5994 // symbol_table: symbol table 5995 // mask: capacity mask 5996 // scratch: - 5997 5998 // Perform a number of probes in the symbol table. 5999 static const int kProbes = 4; 6000 Label found_in_symbol_table; 6001 Label next_probe[kProbes], next_probe_pop_mask[kProbes]; 6002 Register candidate = scratch; // Scratch register contains candidate. 6003 for (int i = 0; i < kProbes; i++) { 6004 // Calculate entry in symbol table. 6005 __ mov(scratch, hash); 6006 if (i > 0) { 6007 __ add(scratch, Immediate(SymbolTable::GetProbeOffset(i))); 6008 } 6009 __ and_(scratch, mask); 6010 6011 // Load the entry from the symbol table. 6012 STATIC_ASSERT(SymbolTable::kEntrySize == 1); 6013 __ mov(candidate, 6014 FieldOperand(symbol_table, 6015 scratch, 6016 times_pointer_size, 6017 SymbolTable::kElementsStartOffset)); 6018 6019 // If entry is undefined no string with this hash can be found. 6020 Factory* factory = masm->isolate()->factory(); 6021 __ cmp(candidate, factory->undefined_value()); 6022 __ j(equal, not_found); 6023 __ cmp(candidate, factory->the_hole_value()); 6024 __ j(equal, &next_probe[i]); 6025 6026 // If length is not 2 the string is not a candidate. 6027 __ cmp(FieldOperand(candidate, String::kLengthOffset), 6028 Immediate(Smi::FromInt(2))); 6029 __ j(not_equal, &next_probe[i]); 6030 6031 // As we are out of registers save the mask on the stack and use that 6032 // register as a temporary. 6033 __ push(mask); 6034 Register temp = mask; 6035 6036 // Check that the candidate is a non-external ASCII string. 6037 __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); 6038 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); 6039 __ JumpIfInstanceTypeIsNotSequentialAscii( 6040 temp, temp, &next_probe_pop_mask[i]); 6041 6042 // Check if the two characters match. 6043 __ mov(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); 6044 __ and_(temp, 0x0000ffff); 6045 __ cmp(chars, temp); 6046 __ j(equal, &found_in_symbol_table); 6047 __ bind(&next_probe_pop_mask[i]); 6048 __ pop(mask); 6049 __ bind(&next_probe[i]); 6050 } 6051 6052 // No matching 2 character string found by probing. 6053 __ jmp(not_found); 6054 6055 // Scratch register contains result when we fall through to here. 6056 Register result = candidate; 6057 __ bind(&found_in_symbol_table); 6058 __ pop(mask); // Pop saved mask from the stack. 6059 if (!result.is(eax)) { 6060 __ mov(eax, result); 6061 } 6062 } 6063 6064 6065 void StringHelper::GenerateHashInit(MacroAssembler* masm, 6066 Register hash, 6067 Register character, 6068 Register scratch) { 6069 // hash = (seed + character) + ((seed + character) << 10); 6070 if (Serializer::enabled()) { 6071 ExternalReference roots_array_start = 6072 ExternalReference::roots_array_start(masm->isolate()); 6073 __ mov(scratch, Immediate(Heap::kHashSeedRootIndex)); 6074 __ mov(scratch, Operand::StaticArray(scratch, 6075 times_pointer_size, 6076 roots_array_start)); 6077 __ SmiUntag(scratch); 6078 __ add(scratch, character); 6079 __ mov(hash, scratch); 6080 __ shl(scratch, 10); 6081 __ add(hash, scratch); 6082 } else { 6083 int32_t seed = masm->isolate()->heap()->HashSeed(); 6084 __ lea(scratch, Operand(character, seed)); 6085 __ shl(scratch, 10); 6086 __ lea(hash, Operand(scratch, character, times_1, seed)); 6087 } 6088 // hash ^= hash >> 6; 6089 __ mov(scratch, hash); 6090 __ shr(scratch, 6); 6091 __ xor_(hash, scratch); 6092 } 6093 6094 6095 void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, 6096 Register hash, 6097 Register character, 6098 Register scratch) { 6099 // hash += character; 6100 __ add(hash, character); 6101 // hash += hash << 10; 6102 __ mov(scratch, hash); 6103 __ shl(scratch, 10); 6104 __ add(hash, scratch); 6105 // hash ^= hash >> 6; 6106 __ mov(scratch, hash); 6107 __ shr(scratch, 6); 6108 __ xor_(hash, scratch); 6109 } 6110 6111 6112 void StringHelper::GenerateHashGetHash(MacroAssembler* masm, 6113 Register hash, 6114 Register scratch) { 6115 // hash += hash << 3; 6116 __ mov(scratch, hash); 6117 __ shl(scratch, 3); 6118 __ add(hash, scratch); 6119 // hash ^= hash >> 11; 6120 __ mov(scratch, hash); 6121 __ shr(scratch, 11); 6122 __ xor_(hash, scratch); 6123 // hash += hash << 15; 6124 __ mov(scratch, hash); 6125 __ shl(scratch, 15); 6126 __ add(hash, scratch); 6127 6128 __ and_(hash, String::kHashBitMask); 6129 6130 // if (hash == 0) hash = 27; 6131 Label hash_not_zero; 6132 __ j(not_zero, &hash_not_zero, Label::kNear); 6133 __ mov(hash, Immediate(StringHasher::kZeroHash)); 6134 __ bind(&hash_not_zero); 6135 } 6136 6137 6138 void SubStringStub::Generate(MacroAssembler* masm) { 6139 Label runtime; 6140 6141 // Stack frame on entry. 6142 // esp[0]: return address 6143 // esp[4]: to 6144 // esp[8]: from 6145 // esp[12]: string 6146 6147 // Make sure first argument is a string. 6148 __ mov(eax, Operand(esp, 3 * kPointerSize)); 6149 STATIC_ASSERT(kSmiTag == 0); 6150 __ JumpIfSmi(eax, &runtime); 6151 Condition is_string = masm->IsObjectStringType(eax, ebx, ebx); 6152 __ j(NegateCondition(is_string), &runtime); 6153 6154 // eax: string 6155 // ebx: instance type 6156 6157 // Calculate length of sub string using the smi values. 6158 __ mov(ecx, Operand(esp, 1 * kPointerSize)); // To index. 6159 __ JumpIfNotSmi(ecx, &runtime); 6160 __ mov(edx, Operand(esp, 2 * kPointerSize)); // From index. 6161 __ JumpIfNotSmi(edx, &runtime); 6162 __ sub(ecx, edx); 6163 __ cmp(ecx, FieldOperand(eax, String::kLengthOffset)); 6164 Label not_original_string; 6165 __ j(not_equal, ¬_original_string, Label::kNear); 6166 Counters* counters = masm->isolate()->counters(); 6167 __ IncrementCounter(counters->sub_string_native(), 1); 6168 __ ret(3 * kPointerSize); 6169 __ bind(¬_original_string); 6170 6171 // eax: string 6172 // ebx: instance type 6173 // ecx: sub string length (smi) 6174 // edx: from index (smi) 6175 // Deal with different string types: update the index if necessary 6176 // and put the underlying string into edi. 6177 Label underlying_unpacked, sliced_string, seq_or_external_string; 6178 // If the string is not indirect, it can only be sequential or external. 6179 STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag)); 6180 STATIC_ASSERT(kIsIndirectStringMask != 0); 6181 __ test(ebx, Immediate(kIsIndirectStringMask)); 6182 __ j(zero, &seq_or_external_string, Label::kNear); 6183 6184 Factory* factory = masm->isolate()->factory(); 6185 __ test(ebx, Immediate(kSlicedNotConsMask)); 6186 __ j(not_zero, &sliced_string, Label::kNear); 6187 // Cons string. Check whether it is flat, then fetch first part. 6188 // Flat cons strings have an empty second part. 6189 __ cmp(FieldOperand(eax, ConsString::kSecondOffset), 6190 factory->empty_string()); 6191 __ j(not_equal, &runtime); 6192 __ mov(edi, FieldOperand(eax, ConsString::kFirstOffset)); 6193 // Update instance type. 6194 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); 6195 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 6196 __ jmp(&underlying_unpacked, Label::kNear); 6197 6198 __ bind(&sliced_string); 6199 // Sliced string. Fetch parent and adjust start index by offset. 6200 __ add(edx, FieldOperand(eax, SlicedString::kOffsetOffset)); 6201 __ mov(edi, FieldOperand(eax, SlicedString::kParentOffset)); 6202 // Update instance type. 6203 __ mov(ebx, FieldOperand(edi, HeapObject::kMapOffset)); 6204 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 6205 __ jmp(&underlying_unpacked, Label::kNear); 6206 6207 __ bind(&seq_or_external_string); 6208 // Sequential or external string. Just move string to the expected register. 6209 __ mov(edi, eax); 6210 6211 __ bind(&underlying_unpacked); 6212 6213 if (FLAG_string_slices) { 6214 Label copy_routine; 6215 // edi: underlying subject string 6216 // ebx: instance type of underlying subject string 6217 // edx: adjusted start index (smi) 6218 // ecx: length (smi) 6219 __ cmp(ecx, Immediate(Smi::FromInt(SlicedString::kMinLength))); 6220 // Short slice. Copy instead of slicing. 6221 __ j(less, ©_routine); 6222 // Allocate new sliced string. At this point we do not reload the instance 6223 // type including the string encoding because we simply rely on the info 6224 // provided by the original string. It does not matter if the original 6225 // string's encoding is wrong because we always have to recheck encoding of 6226 // the newly created string's parent anyways due to externalized strings. 6227 Label two_byte_slice, set_slice_header; 6228 STATIC_ASSERT((kStringEncodingMask & kAsciiStringTag) != 0); 6229 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); 6230 __ test(ebx, Immediate(kStringEncodingMask)); 6231 __ j(zero, &two_byte_slice, Label::kNear); 6232 __ AllocateAsciiSlicedString(eax, ebx, no_reg, &runtime); 6233 __ jmp(&set_slice_header, Label::kNear); 6234 __ bind(&two_byte_slice); 6235 __ AllocateTwoByteSlicedString(eax, ebx, no_reg, &runtime); 6236 __ bind(&set_slice_header); 6237 __ mov(FieldOperand(eax, SlicedString::kLengthOffset), ecx); 6238 __ mov(FieldOperand(eax, SlicedString::kHashFieldOffset), 6239 Immediate(String::kEmptyHashField)); 6240 __ mov(FieldOperand(eax, SlicedString::kParentOffset), edi); 6241 __ mov(FieldOperand(eax, SlicedString::kOffsetOffset), edx); 6242 __ IncrementCounter(counters->sub_string_native(), 1); 6243 __ ret(3 * kPointerSize); 6244 6245 __ bind(©_routine); 6246 } 6247 6248 // edi: underlying subject string 6249 // ebx: instance type of underlying subject string 6250 // edx: adjusted start index (smi) 6251 // ecx: length (smi) 6252 // The subject string can only be external or sequential string of either 6253 // encoding at this point. 6254 Label two_byte_sequential, runtime_drop_two, sequential_string; 6255 STATIC_ASSERT(kExternalStringTag != 0); 6256 STATIC_ASSERT(kSeqStringTag == 0); 6257 __ test_b(ebx, kExternalStringTag); 6258 __ j(zero, &sequential_string); 6259 6260 // Handle external string. 6261 // Rule out short external strings. 6262 STATIC_CHECK(kShortExternalStringTag != 0); 6263 __ test_b(ebx, kShortExternalStringMask); 6264 __ j(not_zero, &runtime); 6265 __ mov(edi, FieldOperand(edi, ExternalString::kResourceDataOffset)); 6266 // Move the pointer so that offset-wise, it looks like a sequential string. 6267 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize); 6268 __ sub(edi, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 6269 6270 __ bind(&sequential_string); 6271 // Stash away (adjusted) index and (underlying) string. 6272 __ push(edx); 6273 __ push(edi); 6274 __ SmiUntag(ecx); 6275 STATIC_ASSERT((kAsciiStringTag & kStringEncodingMask) != 0); 6276 __ test_b(ebx, kStringEncodingMask); 6277 __ j(zero, &two_byte_sequential); 6278 6279 // Sequential ASCII string. Allocate the result. 6280 __ AllocateAsciiString(eax, ecx, ebx, edx, edi, &runtime_drop_two); 6281 6282 // eax: result string 6283 // ecx: result string length 6284 __ mov(edx, esi); // esi used by following code. 6285 // Locate first character of result. 6286 __ mov(edi, eax); 6287 __ add(edi, Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); 6288 // Load string argument and locate character of sub string start. 6289 __ pop(esi); 6290 __ pop(ebx); 6291 __ SmiUntag(ebx); 6292 __ lea(esi, FieldOperand(esi, ebx, times_1, SeqAsciiString::kHeaderSize)); 6293 6294 // eax: result string 6295 // ecx: result length 6296 // edx: original value of esi 6297 // edi: first character of result 6298 // esi: character of sub string start 6299 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); 6300 __ mov(esi, edx); // Restore esi. 6301 __ IncrementCounter(counters->sub_string_native(), 1); 6302 __ ret(3 * kPointerSize); 6303 6304 __ bind(&two_byte_sequential); 6305 // Sequential two-byte string. Allocate the result. 6306 __ AllocateTwoByteString(eax, ecx, ebx, edx, edi, &runtime_drop_two); 6307 6308 // eax: result string 6309 // ecx: result string length 6310 __ mov(edx, esi); // esi used by following code. 6311 // Locate first character of result. 6312 __ mov(edi, eax); 6313 __ add(edi, 6314 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); 6315 // Load string argument and locate character of sub string start. 6316 __ pop(esi); 6317 __ pop(ebx); 6318 // As from is a smi it is 2 times the value which matches the size of a two 6319 // byte character. 6320 STATIC_ASSERT(kSmiTag == 0); 6321 STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1); 6322 __ lea(esi, FieldOperand(esi, ebx, times_1, SeqTwoByteString::kHeaderSize)); 6323 6324 // eax: result string 6325 // ecx: result length 6326 // edx: original value of esi 6327 // edi: first character of result 6328 // esi: character of sub string start 6329 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); 6330 __ mov(esi, edx); // Restore esi. 6331 __ IncrementCounter(counters->sub_string_native(), 1); 6332 __ ret(3 * kPointerSize); 6333 6334 // Drop pushed values on the stack before tail call. 6335 __ bind(&runtime_drop_two); 6336 __ Drop(2); 6337 6338 // Just jump to runtime to create the sub string. 6339 __ bind(&runtime); 6340 __ TailCallRuntime(Runtime::kSubString, 3, 1); 6341 } 6342 6343 6344 void StringCompareStub::GenerateFlatAsciiStringEquals(MacroAssembler* masm, 6345 Register left, 6346 Register right, 6347 Register scratch1, 6348 Register scratch2) { 6349 Register length = scratch1; 6350 6351 // Compare lengths. 6352 Label strings_not_equal, check_zero_length; 6353 __ mov(length, FieldOperand(left, String::kLengthOffset)); 6354 __ cmp(length, FieldOperand(right, String::kLengthOffset)); 6355 __ j(equal, &check_zero_length, Label::kNear); 6356 __ bind(&strings_not_equal); 6357 __ Set(eax, Immediate(Smi::FromInt(NOT_EQUAL))); 6358 __ ret(0); 6359 6360 // Check if the length is zero. 6361 Label compare_chars; 6362 __ bind(&check_zero_length); 6363 STATIC_ASSERT(kSmiTag == 0); 6364 __ test(length, length); 6365 __ j(not_zero, &compare_chars, Label::kNear); 6366 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6367 __ ret(0); 6368 6369 // Compare characters. 6370 __ bind(&compare_chars); 6371 GenerateAsciiCharsCompareLoop(masm, left, right, length, scratch2, 6372 &strings_not_equal, Label::kNear); 6373 6374 // Characters are equal. 6375 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6376 __ ret(0); 6377 } 6378 6379 6380 void StringCompareStub::GenerateCompareFlatAsciiStrings(MacroAssembler* masm, 6381 Register left, 6382 Register right, 6383 Register scratch1, 6384 Register scratch2, 6385 Register scratch3) { 6386 Counters* counters = masm->isolate()->counters(); 6387 __ IncrementCounter(counters->string_compare_native(), 1); 6388 6389 // Find minimum length. 6390 Label left_shorter; 6391 __ mov(scratch1, FieldOperand(left, String::kLengthOffset)); 6392 __ mov(scratch3, scratch1); 6393 __ sub(scratch3, FieldOperand(right, String::kLengthOffset)); 6394 6395 Register length_delta = scratch3; 6396 6397 __ j(less_equal, &left_shorter, Label::kNear); 6398 // Right string is shorter. Change scratch1 to be length of right string. 6399 __ sub(scratch1, length_delta); 6400 __ bind(&left_shorter); 6401 6402 Register min_length = scratch1; 6403 6404 // If either length is zero, just compare lengths. 6405 Label compare_lengths; 6406 __ test(min_length, min_length); 6407 __ j(zero, &compare_lengths, Label::kNear); 6408 6409 // Compare characters. 6410 Label result_not_equal; 6411 GenerateAsciiCharsCompareLoop(masm, left, right, min_length, scratch2, 6412 &result_not_equal, Label::kNear); 6413 6414 // Compare lengths - strings up to min-length are equal. 6415 __ bind(&compare_lengths); 6416 __ test(length_delta, length_delta); 6417 __ j(not_zero, &result_not_equal, Label::kNear); 6418 6419 // Result is EQUAL. 6420 STATIC_ASSERT(EQUAL == 0); 6421 STATIC_ASSERT(kSmiTag == 0); 6422 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6423 __ ret(0); 6424 6425 Label result_greater; 6426 __ bind(&result_not_equal); 6427 __ j(greater, &result_greater, Label::kNear); 6428 6429 // Result is LESS. 6430 __ Set(eax, Immediate(Smi::FromInt(LESS))); 6431 __ ret(0); 6432 6433 // Result is GREATER. 6434 __ bind(&result_greater); 6435 __ Set(eax, Immediate(Smi::FromInt(GREATER))); 6436 __ ret(0); 6437 } 6438 6439 6440 void StringCompareStub::GenerateAsciiCharsCompareLoop( 6441 MacroAssembler* masm, 6442 Register left, 6443 Register right, 6444 Register length, 6445 Register scratch, 6446 Label* chars_not_equal, 6447 Label::Distance chars_not_equal_near) { 6448 // Change index to run from -length to -1 by adding length to string 6449 // start. This means that loop ends when index reaches zero, which 6450 // doesn't need an additional compare. 6451 __ SmiUntag(length); 6452 __ lea(left, 6453 FieldOperand(left, length, times_1, SeqAsciiString::kHeaderSize)); 6454 __ lea(right, 6455 FieldOperand(right, length, times_1, SeqAsciiString::kHeaderSize)); 6456 __ neg(length); 6457 Register index = length; // index = -length; 6458 6459 // Compare loop. 6460 Label loop; 6461 __ bind(&loop); 6462 __ mov_b(scratch, Operand(left, index, times_1, 0)); 6463 __ cmpb(scratch, Operand(right, index, times_1, 0)); 6464 __ j(not_equal, chars_not_equal, chars_not_equal_near); 6465 __ inc(index); 6466 __ j(not_zero, &loop); 6467 } 6468 6469 6470 void StringCompareStub::Generate(MacroAssembler* masm) { 6471 Label runtime; 6472 6473 // Stack frame on entry. 6474 // esp[0]: return address 6475 // esp[4]: right string 6476 // esp[8]: left string 6477 6478 __ mov(edx, Operand(esp, 2 * kPointerSize)); // left 6479 __ mov(eax, Operand(esp, 1 * kPointerSize)); // right 6480 6481 Label not_same; 6482 __ cmp(edx, eax); 6483 __ j(not_equal, ¬_same, Label::kNear); 6484 STATIC_ASSERT(EQUAL == 0); 6485 STATIC_ASSERT(kSmiTag == 0); 6486 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6487 __ IncrementCounter(masm->isolate()->counters()->string_compare_native(), 1); 6488 __ ret(2 * kPointerSize); 6489 6490 __ bind(¬_same); 6491 6492 // Check that both objects are sequential ASCII strings. 6493 __ JumpIfNotBothSequentialAsciiStrings(edx, eax, ecx, ebx, &runtime); 6494 6495 // Compare flat ASCII strings. 6496 // Drop arguments from the stack. 6497 __ pop(ecx); 6498 __ add(esp, Immediate(2 * kPointerSize)); 6499 __ push(ecx); 6500 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); 6501 6502 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) 6503 // tagged as a small integer. 6504 __ bind(&runtime); 6505 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 6506 } 6507 6508 6509 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { 6510 ASSERT(state_ == CompareIC::SMIS); 6511 Label miss; 6512 __ mov(ecx, edx); 6513 __ or_(ecx, eax); 6514 __ JumpIfNotSmi(ecx, &miss, Label::kNear); 6515 6516 if (GetCondition() == equal) { 6517 // For equality we do not care about the sign of the result. 6518 __ sub(eax, edx); 6519 } else { 6520 Label done; 6521 __ sub(edx, eax); 6522 __ j(no_overflow, &done, Label::kNear); 6523 // Correct sign of result in case of overflow. 6524 __ not_(edx); 6525 __ bind(&done); 6526 __ mov(eax, edx); 6527 } 6528 __ ret(0); 6529 6530 __ bind(&miss); 6531 GenerateMiss(masm); 6532 } 6533 6534 6535 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) { 6536 ASSERT(state_ == CompareIC::HEAP_NUMBERS); 6537 6538 Label generic_stub; 6539 Label unordered, maybe_undefined1, maybe_undefined2; 6540 Label miss; 6541 __ mov(ecx, edx); 6542 __ and_(ecx, eax); 6543 __ JumpIfSmi(ecx, &generic_stub, Label::kNear); 6544 6545 __ CmpObjectType(eax, HEAP_NUMBER_TYPE, ecx); 6546 __ j(not_equal, &maybe_undefined1, Label::kNear); 6547 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); 6548 __ j(not_equal, &maybe_undefined2, Label::kNear); 6549 6550 // Inlining the double comparison and falling back to the general compare 6551 // stub if NaN is involved or SS2 or CMOV is unsupported. 6552 if (CpuFeatures::IsSupported(SSE2) && CpuFeatures::IsSupported(CMOV)) { 6553 CpuFeatures::Scope scope1(SSE2); 6554 CpuFeatures::Scope scope2(CMOV); 6555 6556 // Load left and right operand 6557 __ movdbl(xmm0, FieldOperand(edx, HeapNumber::kValueOffset)); 6558 __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset)); 6559 6560 // Compare operands 6561 __ ucomisd(xmm0, xmm1); 6562 6563 // Don't base result on EFLAGS when a NaN is involved. 6564 __ j(parity_even, &unordered, Label::kNear); 6565 6566 // Return a result of -1, 0, or 1, based on EFLAGS. 6567 // Performing mov, because xor would destroy the flag register. 6568 __ mov(eax, 0); // equal 6569 __ mov(ecx, Immediate(Smi::FromInt(1))); 6570 __ cmov(above, eax, ecx); 6571 __ mov(ecx, Immediate(Smi::FromInt(-1))); 6572 __ cmov(below, eax, ecx); 6573 __ ret(0); 6574 } 6575 6576 __ bind(&unordered); 6577 CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS); 6578 __ bind(&generic_stub); 6579 __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET); 6580 6581 __ bind(&maybe_undefined1); 6582 if (Token::IsOrderedRelationalCompareOp(op_)) { 6583 __ cmp(eax, Immediate(masm->isolate()->factory()->undefined_value())); 6584 __ j(not_equal, &miss); 6585 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, ecx); 6586 __ j(not_equal, &maybe_undefined2, Label::kNear); 6587 __ jmp(&unordered); 6588 } 6589 6590 __ bind(&maybe_undefined2); 6591 if (Token::IsOrderedRelationalCompareOp(op_)) { 6592 __ cmp(edx, Immediate(masm->isolate()->factory()->undefined_value())); 6593 __ j(equal, &unordered); 6594 } 6595 6596 __ bind(&miss); 6597 GenerateMiss(masm); 6598 } 6599 6600 6601 void ICCompareStub::GenerateSymbols(MacroAssembler* masm) { 6602 ASSERT(state_ == CompareIC::SYMBOLS); 6603 ASSERT(GetCondition() == equal); 6604 6605 // Registers containing left and right operands respectively. 6606 Register left = edx; 6607 Register right = eax; 6608 Register tmp1 = ecx; 6609 Register tmp2 = ebx; 6610 6611 // Check that both operands are heap objects. 6612 Label miss; 6613 __ mov(tmp1, left); 6614 STATIC_ASSERT(kSmiTag == 0); 6615 __ and_(tmp1, right); 6616 __ JumpIfSmi(tmp1, &miss, Label::kNear); 6617 6618 // Check that both operands are symbols. 6619 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); 6620 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); 6621 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); 6622 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); 6623 STATIC_ASSERT(kSymbolTag != 0); 6624 __ and_(tmp1, tmp2); 6625 __ test(tmp1, Immediate(kIsSymbolMask)); 6626 __ j(zero, &miss, Label::kNear); 6627 6628 // Symbols are compared by identity. 6629 Label done; 6630 __ cmp(left, right); 6631 // Make sure eax is non-zero. At this point input operands are 6632 // guaranteed to be non-zero. 6633 ASSERT(right.is(eax)); 6634 __ j(not_equal, &done, Label::kNear); 6635 STATIC_ASSERT(EQUAL == 0); 6636 STATIC_ASSERT(kSmiTag == 0); 6637 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6638 __ bind(&done); 6639 __ ret(0); 6640 6641 __ bind(&miss); 6642 GenerateMiss(masm); 6643 } 6644 6645 6646 void ICCompareStub::GenerateStrings(MacroAssembler* masm) { 6647 ASSERT(state_ == CompareIC::STRINGS); 6648 Label miss; 6649 6650 bool equality = Token::IsEqualityOp(op_); 6651 6652 // Registers containing left and right operands respectively. 6653 Register left = edx; 6654 Register right = eax; 6655 Register tmp1 = ecx; 6656 Register tmp2 = ebx; 6657 Register tmp3 = edi; 6658 6659 // Check that both operands are heap objects. 6660 __ mov(tmp1, left); 6661 STATIC_ASSERT(kSmiTag == 0); 6662 __ and_(tmp1, right); 6663 __ JumpIfSmi(tmp1, &miss); 6664 6665 // Check that both operands are strings. This leaves the instance 6666 // types loaded in tmp1 and tmp2. 6667 __ mov(tmp1, FieldOperand(left, HeapObject::kMapOffset)); 6668 __ mov(tmp2, FieldOperand(right, HeapObject::kMapOffset)); 6669 __ movzx_b(tmp1, FieldOperand(tmp1, Map::kInstanceTypeOffset)); 6670 __ movzx_b(tmp2, FieldOperand(tmp2, Map::kInstanceTypeOffset)); 6671 __ mov(tmp3, tmp1); 6672 STATIC_ASSERT(kNotStringTag != 0); 6673 __ or_(tmp3, tmp2); 6674 __ test(tmp3, Immediate(kIsNotStringMask)); 6675 __ j(not_zero, &miss); 6676 6677 // Fast check for identical strings. 6678 Label not_same; 6679 __ cmp(left, right); 6680 __ j(not_equal, ¬_same, Label::kNear); 6681 STATIC_ASSERT(EQUAL == 0); 6682 STATIC_ASSERT(kSmiTag == 0); 6683 __ Set(eax, Immediate(Smi::FromInt(EQUAL))); 6684 __ ret(0); 6685 6686 // Handle not identical strings. 6687 __ bind(¬_same); 6688 6689 // Check that both strings are symbols. If they are, we're done 6690 // because we already know they are not identical. But in the case of 6691 // non-equality compare, we still need to determine the order. 6692 if (equality) { 6693 Label do_compare; 6694 STATIC_ASSERT(kSymbolTag != 0); 6695 __ and_(tmp1, tmp2); 6696 __ test(tmp1, Immediate(kIsSymbolMask)); 6697 __ j(zero, &do_compare, Label::kNear); 6698 // Make sure eax is non-zero. At this point input operands are 6699 // guaranteed to be non-zero. 6700 ASSERT(right.is(eax)); 6701 __ ret(0); 6702 __ bind(&do_compare); 6703 } 6704 6705 // Check that both strings are sequential ASCII. 6706 Label runtime; 6707 __ JumpIfNotBothSequentialAsciiStrings(left, right, tmp1, tmp2, &runtime); 6708 6709 // Compare flat ASCII strings. Returns when done. 6710 if (equality) { 6711 StringCompareStub::GenerateFlatAsciiStringEquals( 6712 masm, left, right, tmp1, tmp2); 6713 } else { 6714 StringCompareStub::GenerateCompareFlatAsciiStrings( 6715 masm, left, right, tmp1, tmp2, tmp3); 6716 } 6717 6718 // Handle more complex cases in runtime. 6719 __ bind(&runtime); 6720 __ pop(tmp1); // Return address. 6721 __ push(left); 6722 __ push(right); 6723 __ push(tmp1); 6724 if (equality) { 6725 __ TailCallRuntime(Runtime::kStringEquals, 2, 1); 6726 } else { 6727 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); 6728 } 6729 6730 __ bind(&miss); 6731 GenerateMiss(masm); 6732 } 6733 6734 6735 void ICCompareStub::GenerateObjects(MacroAssembler* masm) { 6736 ASSERT(state_ == CompareIC::OBJECTS); 6737 Label miss; 6738 __ mov(ecx, edx); 6739 __ and_(ecx, eax); 6740 __ JumpIfSmi(ecx, &miss, Label::kNear); 6741 6742 __ CmpObjectType(eax, JS_OBJECT_TYPE, ecx); 6743 __ j(not_equal, &miss, Label::kNear); 6744 __ CmpObjectType(edx, JS_OBJECT_TYPE, ecx); 6745 __ j(not_equal, &miss, Label::kNear); 6746 6747 ASSERT(GetCondition() == equal); 6748 __ sub(eax, edx); 6749 __ ret(0); 6750 6751 __ bind(&miss); 6752 GenerateMiss(masm); 6753 } 6754 6755 6756 void ICCompareStub::GenerateKnownObjects(MacroAssembler* masm) { 6757 Label miss; 6758 __ mov(ecx, edx); 6759 __ and_(ecx, eax); 6760 __ JumpIfSmi(ecx, &miss, Label::kNear); 6761 6762 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 6763 __ mov(ebx, FieldOperand(edx, HeapObject::kMapOffset)); 6764 __ cmp(ecx, known_map_); 6765 __ j(not_equal, &miss, Label::kNear); 6766 __ cmp(ebx, known_map_); 6767 __ j(not_equal, &miss, Label::kNear); 6768 6769 __ sub(eax, edx); 6770 __ ret(0); 6771 6772 __ bind(&miss); 6773 GenerateMiss(masm); 6774 } 6775 6776 6777 void ICCompareStub::GenerateMiss(MacroAssembler* masm) { 6778 { 6779 // Call the runtime system in a fresh internal frame. 6780 ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss), 6781 masm->isolate()); 6782 FrameScope scope(masm, StackFrame::INTERNAL); 6783 __ push(edx); // Preserve edx and eax. 6784 __ push(eax); 6785 __ push(edx); // And also use them as the arguments. 6786 __ push(eax); 6787 __ push(Immediate(Smi::FromInt(op_))); 6788 __ CallExternalReference(miss, 3); 6789 // Compute the entry point of the rewritten stub. 6790 __ lea(edi, FieldOperand(eax, Code::kHeaderSize)); 6791 __ pop(eax); 6792 __ pop(edx); 6793 } 6794 6795 // Do a tail call to the rewritten stub. 6796 __ jmp(edi); 6797 } 6798 6799 6800 // Helper function used to check that the dictionary doesn't contain 6801 // the property. This function may return false negatives, so miss_label 6802 // must always call a backup property check that is complete. 6803 // This function is safe to call if the receiver has fast properties. 6804 // Name must be a symbol and receiver must be a heap object. 6805 void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, 6806 Label* miss, 6807 Label* done, 6808 Register properties, 6809 Handle<String> name, 6810 Register r0) { 6811 ASSERT(name->IsSymbol()); 6812 6813 // If names of slots in range from 1 to kProbes - 1 for the hash value are 6814 // not equal to the name and kProbes-th slot is not used (its name is the 6815 // undefined value), it guarantees the hash table doesn't contain the 6816 // property. It's true even if some slots represent deleted properties 6817 // (their names are the hole value). 6818 for (int i = 0; i < kInlinedProbes; i++) { 6819 // Compute the masked index: (hash + i + i * i) & mask. 6820 Register index = r0; 6821 // Capacity is smi 2^n. 6822 __ mov(index, FieldOperand(properties, kCapacityOffset)); 6823 __ dec(index); 6824 __ and_(index, 6825 Immediate(Smi::FromInt(name->Hash() + 6826 StringDictionary::GetProbeOffset(i)))); 6827 6828 // Scale the index by multiplying by the entry size. 6829 ASSERT(StringDictionary::kEntrySize == 3); 6830 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. 6831 Register entity_name = r0; 6832 // Having undefined at this place means the name is not contained. 6833 ASSERT_EQ(kSmiTagSize, 1); 6834 __ mov(entity_name, Operand(properties, index, times_half_pointer_size, 6835 kElementsStartOffset - kHeapObjectTag)); 6836 __ cmp(entity_name, masm->isolate()->factory()->undefined_value()); 6837 __ j(equal, done); 6838 6839 // Stop if found the property. 6840 __ cmp(entity_name, Handle<String>(name)); 6841 __ j(equal, miss); 6842 6843 Label the_hole; 6844 // Check for the hole and skip. 6845 __ cmp(entity_name, masm->isolate()->factory()->the_hole_value()); 6846 __ j(equal, &the_hole, Label::kNear); 6847 6848 // Check if the entry name is not a symbol. 6849 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); 6850 __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), 6851 kIsSymbolMask); 6852 __ j(zero, miss); 6853 __ bind(&the_hole); 6854 } 6855 6856 StringDictionaryLookupStub stub(properties, 6857 r0, 6858 r0, 6859 StringDictionaryLookupStub::NEGATIVE_LOOKUP); 6860 __ push(Immediate(Handle<Object>(name))); 6861 __ push(Immediate(name->Hash())); 6862 __ CallStub(&stub); 6863 __ test(r0, r0); 6864 __ j(not_zero, miss); 6865 __ jmp(done); 6866 } 6867 6868 6869 // Probe the string dictionary in the |elements| register. Jump to the 6870 // |done| label if a property with the given name is found leaving the 6871 // index into the dictionary in |r0|. Jump to the |miss| label 6872 // otherwise. 6873 void StringDictionaryLookupStub::GeneratePositiveLookup(MacroAssembler* masm, 6874 Label* miss, 6875 Label* done, 6876 Register elements, 6877 Register name, 6878 Register r0, 6879 Register r1) { 6880 ASSERT(!elements.is(r0)); 6881 ASSERT(!elements.is(r1)); 6882 ASSERT(!name.is(r0)); 6883 ASSERT(!name.is(r1)); 6884 6885 // Assert that name contains a string. 6886 if (FLAG_debug_code) __ AbortIfNotString(name); 6887 6888 __ mov(r1, FieldOperand(elements, kCapacityOffset)); 6889 __ shr(r1, kSmiTagSize); // convert smi to int 6890 __ dec(r1); 6891 6892 // Generate an unrolled loop that performs a few probes before 6893 // giving up. Measurements done on Gmail indicate that 2 probes 6894 // cover ~93% of loads from dictionaries. 6895 for (int i = 0; i < kInlinedProbes; i++) { 6896 // Compute the masked index: (hash + i + i * i) & mask. 6897 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); 6898 __ shr(r0, String::kHashShift); 6899 if (i > 0) { 6900 __ add(r0, Immediate(StringDictionary::GetProbeOffset(i))); 6901 } 6902 __ and_(r0, r1); 6903 6904 // Scale the index by multiplying by the entry size. 6905 ASSERT(StringDictionary::kEntrySize == 3); 6906 __ lea(r0, Operand(r0, r0, times_2, 0)); // r0 = r0 * 3 6907 6908 // Check if the key is identical to the name. 6909 __ cmp(name, Operand(elements, 6910 r0, 6911 times_4, 6912 kElementsStartOffset - kHeapObjectTag)); 6913 __ j(equal, done); 6914 } 6915 6916 StringDictionaryLookupStub stub(elements, 6917 r1, 6918 r0, 6919 POSITIVE_LOOKUP); 6920 __ push(name); 6921 __ mov(r0, FieldOperand(name, String::kHashFieldOffset)); 6922 __ shr(r0, String::kHashShift); 6923 __ push(r0); 6924 __ CallStub(&stub); 6925 6926 __ test(r1, r1); 6927 __ j(zero, miss); 6928 __ jmp(done); 6929 } 6930 6931 6932 void StringDictionaryLookupStub::Generate(MacroAssembler* masm) { 6933 // This stub overrides SometimesSetsUpAFrame() to return false. That means 6934 // we cannot call anything that could cause a GC from this stub. 6935 // Stack frame on entry: 6936 // esp[0 * kPointerSize]: return address. 6937 // esp[1 * kPointerSize]: key's hash. 6938 // esp[2 * kPointerSize]: key. 6939 // Registers: 6940 // dictionary_: StringDictionary to probe. 6941 // result_: used as scratch. 6942 // index_: will hold an index of entry if lookup is successful. 6943 // might alias with result_. 6944 // Returns: 6945 // result_ is zero if lookup failed, non zero otherwise. 6946 6947 Label in_dictionary, maybe_in_dictionary, not_in_dictionary; 6948 6949 Register scratch = result_; 6950 6951 __ mov(scratch, FieldOperand(dictionary_, kCapacityOffset)); 6952 __ dec(scratch); 6953 __ SmiUntag(scratch); 6954 __ push(scratch); 6955 6956 // If names of slots in range from 1 to kProbes - 1 for the hash value are 6957 // not equal to the name and kProbes-th slot is not used (its name is the 6958 // undefined value), it guarantees the hash table doesn't contain the 6959 // property. It's true even if some slots represent deleted properties 6960 // (their names are the null value). 6961 for (int i = kInlinedProbes; i < kTotalProbes; i++) { 6962 // Compute the masked index: (hash + i + i * i) & mask. 6963 __ mov(scratch, Operand(esp, 2 * kPointerSize)); 6964 if (i > 0) { 6965 __ add(scratch, Immediate(StringDictionary::GetProbeOffset(i))); 6966 } 6967 __ and_(scratch, Operand(esp, 0)); 6968 6969 // Scale the index by multiplying by the entry size. 6970 ASSERT(StringDictionary::kEntrySize == 3); 6971 __ lea(index_, Operand(scratch, scratch, times_2, 0)); // index *= 3. 6972 6973 // Having undefined at this place means the name is not contained. 6974 ASSERT_EQ(kSmiTagSize, 1); 6975 __ mov(scratch, Operand(dictionary_, 6976 index_, 6977 times_pointer_size, 6978 kElementsStartOffset - kHeapObjectTag)); 6979 __ cmp(scratch, masm->isolate()->factory()->undefined_value()); 6980 __ j(equal, ¬_in_dictionary); 6981 6982 // Stop if found the property. 6983 __ cmp(scratch, Operand(esp, 3 * kPointerSize)); 6984 __ j(equal, &in_dictionary); 6985 6986 if (i != kTotalProbes - 1 && mode_ == NEGATIVE_LOOKUP) { 6987 // If we hit a non symbol key during negative lookup 6988 // we have to bailout as this key might be equal to the 6989 // key we are looking for. 6990 6991 // Check if the entry name is not a symbol. 6992 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); 6993 __ test_b(FieldOperand(scratch, Map::kInstanceTypeOffset), 6994 kIsSymbolMask); 6995 __ j(zero, &maybe_in_dictionary); 6996 } 6997 } 6998 6999 __ bind(&maybe_in_dictionary); 7000 // If we are doing negative lookup then probing failure should be 7001 // treated as a lookup success. For positive lookup probing failure 7002 // should be treated as lookup failure. 7003 if (mode_ == POSITIVE_LOOKUP) { 7004 __ mov(result_, Immediate(0)); 7005 __ Drop(1); 7006 __ ret(2 * kPointerSize); 7007 } 7008 7009 __ bind(&in_dictionary); 7010 __ mov(result_, Immediate(1)); 7011 __ Drop(1); 7012 __ ret(2 * kPointerSize); 7013 7014 __ bind(¬_in_dictionary); 7015 __ mov(result_, Immediate(0)); 7016 __ Drop(1); 7017 __ ret(2 * kPointerSize); 7018 } 7019 7020 7021 struct AheadOfTimeWriteBarrierStubList { 7022 Register object, value, address; 7023 RememberedSetAction action; 7024 }; 7025 7026 7027 #define REG(Name) { kRegister_ ## Name ## _Code } 7028 7029 static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = { 7030 // Used in RegExpExecStub. 7031 { REG(ebx), REG(eax), REG(edi), EMIT_REMEMBERED_SET }, 7032 // Used in CompileArrayPushCall. 7033 { REG(ebx), REG(ecx), REG(edx), EMIT_REMEMBERED_SET }, 7034 { REG(ebx), REG(edi), REG(edx), OMIT_REMEMBERED_SET }, 7035 // Used in CompileStoreGlobal and CallFunctionStub. 7036 { REG(ebx), REG(ecx), REG(edx), OMIT_REMEMBERED_SET }, 7037 // Used in StoreStubCompiler::CompileStoreField and 7038 // KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField. 7039 { REG(edx), REG(ecx), REG(ebx), EMIT_REMEMBERED_SET }, 7040 // GenerateStoreField calls the stub with two different permutations of 7041 // registers. This is the second. 7042 { REG(ebx), REG(ecx), REG(edx), EMIT_REMEMBERED_SET }, 7043 // StoreIC::GenerateNormal via GenerateDictionaryStore 7044 { REG(ebx), REG(edi), REG(edx), EMIT_REMEMBERED_SET }, 7045 // KeyedStoreIC::GenerateGeneric. 7046 { REG(ebx), REG(edx), REG(ecx), EMIT_REMEMBERED_SET}, 7047 // KeyedStoreStubCompiler::GenerateStoreFastElement. 7048 { REG(edi), REG(ebx), REG(ecx), EMIT_REMEMBERED_SET}, 7049 { REG(edx), REG(edi), REG(ebx), EMIT_REMEMBERED_SET}, 7050 // ElementsTransitionGenerator::GenerateSmiOnlyToObject 7051 // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble 7052 // and ElementsTransitionGenerator::GenerateDoubleToObject 7053 { REG(edx), REG(ebx), REG(edi), EMIT_REMEMBERED_SET}, 7054 { REG(edx), REG(ebx), REG(edi), OMIT_REMEMBERED_SET}, 7055 // ElementsTransitionGenerator::GenerateDoubleToObject 7056 { REG(eax), REG(edx), REG(esi), EMIT_REMEMBERED_SET}, 7057 { REG(edx), REG(eax), REG(edi), EMIT_REMEMBERED_SET}, 7058 // StoreArrayLiteralElementStub::Generate 7059 { REG(ebx), REG(eax), REG(ecx), EMIT_REMEMBERED_SET}, 7060 // Null termination. 7061 { REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET} 7062 }; 7063 7064 #undef REG 7065 7066 bool RecordWriteStub::IsPregenerated() { 7067 for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; 7068 !entry->object.is(no_reg); 7069 entry++) { 7070 if (object_.is(entry->object) && 7071 value_.is(entry->value) && 7072 address_.is(entry->address) && 7073 remembered_set_action_ == entry->action && 7074 save_fp_regs_mode_ == kDontSaveFPRegs) { 7075 return true; 7076 } 7077 } 7078 return false; 7079 } 7080 7081 7082 void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime() { 7083 StoreBufferOverflowStub stub1(kDontSaveFPRegs); 7084 stub1.GetCode()->set_is_pregenerated(true); 7085 7086 CpuFeatures::TryForceFeatureScope scope(SSE2); 7087 if (CpuFeatures::IsSupported(SSE2)) { 7088 StoreBufferOverflowStub stub2(kSaveFPRegs); 7089 stub2.GetCode()->set_is_pregenerated(true); 7090 } 7091 } 7092 7093 7094 void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() { 7095 for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; 7096 !entry->object.is(no_reg); 7097 entry++) { 7098 RecordWriteStub stub(entry->object, 7099 entry->value, 7100 entry->address, 7101 entry->action, 7102 kDontSaveFPRegs); 7103 stub.GetCode()->set_is_pregenerated(true); 7104 } 7105 } 7106 7107 7108 // Takes the input in 3 registers: address_ value_ and object_. A pointer to 7109 // the value has just been written into the object, now this stub makes sure 7110 // we keep the GC informed. The word in the object where the value has been 7111 // written is in the address register. 7112 void RecordWriteStub::Generate(MacroAssembler* masm) { 7113 Label skip_to_incremental_noncompacting; 7114 Label skip_to_incremental_compacting; 7115 7116 // The first two instructions are generated with labels so as to get the 7117 // offset fixed up correctly by the bind(Label*) call. We patch it back and 7118 // forth between a compare instructions (a nop in this position) and the 7119 // real branch when we start and stop incremental heap marking. 7120 __ jmp(&skip_to_incremental_noncompacting, Label::kNear); 7121 __ jmp(&skip_to_incremental_compacting, Label::kFar); 7122 7123 if (remembered_set_action_ == EMIT_REMEMBERED_SET) { 7124 __ RememberedSetHelper(object_, 7125 address_, 7126 value_, 7127 save_fp_regs_mode_, 7128 MacroAssembler::kReturnAtEnd); 7129 } else { 7130 __ ret(0); 7131 } 7132 7133 __ bind(&skip_to_incremental_noncompacting); 7134 GenerateIncremental(masm, INCREMENTAL); 7135 7136 __ bind(&skip_to_incremental_compacting); 7137 GenerateIncremental(masm, INCREMENTAL_COMPACTION); 7138 7139 // Initial mode of the stub is expected to be STORE_BUFFER_ONLY. 7140 // Will be checked in IncrementalMarking::ActivateGeneratedStub. 7141 masm->set_byte_at(0, kTwoByteNopInstruction); 7142 masm->set_byte_at(2, kFiveByteNopInstruction); 7143 } 7144 7145 7146 void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) { 7147 regs_.Save(masm); 7148 7149 if (remembered_set_action_ == EMIT_REMEMBERED_SET) { 7150 Label dont_need_remembered_set; 7151 7152 __ mov(regs_.scratch0(), Operand(regs_.address(), 0)); 7153 __ JumpIfNotInNewSpace(regs_.scratch0(), // Value. 7154 regs_.scratch0(), 7155 &dont_need_remembered_set); 7156 7157 __ CheckPageFlag(regs_.object(), 7158 regs_.scratch0(), 7159 1 << MemoryChunk::SCAN_ON_SCAVENGE, 7160 not_zero, 7161 &dont_need_remembered_set); 7162 7163 // First notify the incremental marker if necessary, then update the 7164 // remembered set. 7165 CheckNeedsToInformIncrementalMarker( 7166 masm, 7167 kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, 7168 mode); 7169 InformIncrementalMarker(masm, mode); 7170 regs_.Restore(masm); 7171 __ RememberedSetHelper(object_, 7172 address_, 7173 value_, 7174 save_fp_regs_mode_, 7175 MacroAssembler::kReturnAtEnd); 7176 7177 __ bind(&dont_need_remembered_set); 7178 } 7179 7180 CheckNeedsToInformIncrementalMarker( 7181 masm, 7182 kReturnOnNoNeedToInformIncrementalMarker, 7183 mode); 7184 InformIncrementalMarker(masm, mode); 7185 regs_.Restore(masm); 7186 __ ret(0); 7187 } 7188 7189 7190 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm, Mode mode) { 7191 regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode_); 7192 int argument_count = 3; 7193 __ PrepareCallCFunction(argument_count, regs_.scratch0()); 7194 __ mov(Operand(esp, 0 * kPointerSize), regs_.object()); 7195 if (mode == INCREMENTAL_COMPACTION) { 7196 __ mov(Operand(esp, 1 * kPointerSize), regs_.address()); // Slot. 7197 } else { 7198 ASSERT(mode == INCREMENTAL); 7199 __ mov(regs_.scratch0(), Operand(regs_.address(), 0)); 7200 __ mov(Operand(esp, 1 * kPointerSize), regs_.scratch0()); // Value. 7201 } 7202 __ mov(Operand(esp, 2 * kPointerSize), 7203 Immediate(ExternalReference::isolate_address())); 7204 7205 AllowExternalCallThatCantCauseGC scope(masm); 7206 if (mode == INCREMENTAL_COMPACTION) { 7207 __ CallCFunction( 7208 ExternalReference::incremental_evacuation_record_write_function( 7209 masm->isolate()), 7210 argument_count); 7211 } else { 7212 ASSERT(mode == INCREMENTAL); 7213 __ CallCFunction( 7214 ExternalReference::incremental_marking_record_write_function( 7215 masm->isolate()), 7216 argument_count); 7217 } 7218 regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode_); 7219 } 7220 7221 7222 void RecordWriteStub::CheckNeedsToInformIncrementalMarker( 7223 MacroAssembler* masm, 7224 OnNoNeedToInformIncrementalMarker on_no_need, 7225 Mode mode) { 7226 Label object_is_black, need_incremental, need_incremental_pop_object; 7227 7228 // Let's look at the color of the object: If it is not black we don't have 7229 // to inform the incremental marker. 7230 __ JumpIfBlack(regs_.object(), 7231 regs_.scratch0(), 7232 regs_.scratch1(), 7233 &object_is_black, 7234 Label::kNear); 7235 7236 regs_.Restore(masm); 7237 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { 7238 __ RememberedSetHelper(object_, 7239 address_, 7240 value_, 7241 save_fp_regs_mode_, 7242 MacroAssembler::kReturnAtEnd); 7243 } else { 7244 __ ret(0); 7245 } 7246 7247 __ bind(&object_is_black); 7248 7249 // Get the value from the slot. 7250 __ mov(regs_.scratch0(), Operand(regs_.address(), 0)); 7251 7252 if (mode == INCREMENTAL_COMPACTION) { 7253 Label ensure_not_white; 7254 7255 __ CheckPageFlag(regs_.scratch0(), // Contains value. 7256 regs_.scratch1(), // Scratch. 7257 MemoryChunk::kEvacuationCandidateMask, 7258 zero, 7259 &ensure_not_white, 7260 Label::kNear); 7261 7262 __ CheckPageFlag(regs_.object(), 7263 regs_.scratch1(), // Scratch. 7264 MemoryChunk::kSkipEvacuationSlotsRecordingMask, 7265 not_zero, 7266 &ensure_not_white, 7267 Label::kNear); 7268 7269 __ jmp(&need_incremental); 7270 7271 __ bind(&ensure_not_white); 7272 } 7273 7274 // We need an extra register for this, so we push the object register 7275 // temporarily. 7276 __ push(regs_.object()); 7277 __ EnsureNotWhite(regs_.scratch0(), // The value. 7278 regs_.scratch1(), // Scratch. 7279 regs_.object(), // Scratch. 7280 &need_incremental_pop_object, 7281 Label::kNear); 7282 __ pop(regs_.object()); 7283 7284 regs_.Restore(masm); 7285 if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) { 7286 __ RememberedSetHelper(object_, 7287 address_, 7288 value_, 7289 save_fp_regs_mode_, 7290 MacroAssembler::kReturnAtEnd); 7291 } else { 7292 __ ret(0); 7293 } 7294 7295 __ bind(&need_incremental_pop_object); 7296 __ pop(regs_.object()); 7297 7298 __ bind(&need_incremental); 7299 7300 // Fall through when we need to inform the incremental marker. 7301 } 7302 7303 7304 void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) { 7305 // ----------- S t a t e ------------- 7306 // -- eax : element value to store 7307 // -- ebx : array literal 7308 // -- edi : map of array literal 7309 // -- ecx : element index as smi 7310 // -- edx : array literal index in function 7311 // -- esp[0] : return address 7312 // ----------------------------------- 7313 7314 Label element_done; 7315 Label double_elements; 7316 Label smi_element; 7317 Label slow_elements; 7318 Label slow_elements_from_double; 7319 Label fast_elements; 7320 7321 __ CheckFastElements(edi, &double_elements); 7322 7323 // FAST_SMI_ONLY_ELEMENTS or FAST_ELEMENTS 7324 __ JumpIfSmi(eax, &smi_element); 7325 __ CheckFastSmiOnlyElements(edi, &fast_elements, Label::kNear); 7326 7327 // Store into the array literal requires a elements transition. Call into 7328 // the runtime. 7329 7330 __ bind(&slow_elements); 7331 __ pop(edi); // Pop return address and remember to put back later for tail 7332 // call. 7333 __ push(ebx); 7334 __ push(ecx); 7335 __ push(eax); 7336 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 7337 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); 7338 __ push(edx); 7339 __ push(edi); // Return return address so that tail call returns to right 7340 // place. 7341 __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1); 7342 7343 __ bind(&slow_elements_from_double); 7344 __ pop(edx); 7345 __ jmp(&slow_elements); 7346 7347 // Array literal has ElementsKind of FAST_ELEMENTS and value is an object. 7348 __ bind(&fast_elements); 7349 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); 7350 __ lea(ecx, FieldOperand(ebx, ecx, times_half_pointer_size, 7351 FixedArrayBase::kHeaderSize)); 7352 __ mov(Operand(ecx, 0), eax); 7353 // Update the write barrier for the array store. 7354 __ RecordWrite(ebx, ecx, eax, 7355 kDontSaveFPRegs, 7356 EMIT_REMEMBERED_SET, 7357 OMIT_SMI_CHECK); 7358 __ ret(0); 7359 7360 // Array literal has ElementsKind of FAST_SMI_ONLY_ELEMENTS or 7361 // FAST_ELEMENTS, and value is Smi. 7362 __ bind(&smi_element); 7363 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset)); 7364 __ mov(FieldOperand(ebx, ecx, times_half_pointer_size, 7365 FixedArrayBase::kHeaderSize), eax); 7366 __ ret(0); 7367 7368 // Array literal has ElementsKind of FAST_DOUBLE_ELEMENTS. 7369 __ bind(&double_elements); 7370 7371 __ push(edx); 7372 __ mov(edx, FieldOperand(ebx, JSObject::kElementsOffset)); 7373 __ StoreNumberToDoubleElements(eax, 7374 edx, 7375 ecx, 7376 edi, 7377 xmm0, 7378 &slow_elements_from_double, 7379 false); 7380 __ pop(edx); 7381 __ ret(0); 7382 } 7383 7384 #undef __ 7385 7386 } } // namespace v8::internal 7387 7388 #endif // V8_TARGET_ARCH_IA32 7389