| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 // Try to allocate the context in new space. | 118 // Try to allocate the context in new space. |
| 119 Label gc; | 119 Label gc; |
| 120 int length = slots_ + Context::MIN_CONTEXT_SLOTS; | 120 int length = slots_ + Context::MIN_CONTEXT_SLOTS; |
| 121 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, | 121 __ AllocateInNewSpace((length * kPointerSize) + FixedArray::kHeaderSize, |
| 122 rax, rbx, rcx, &gc, TAG_OBJECT); | 122 rax, rbx, rcx, &gc, TAG_OBJECT); |
| 123 | 123 |
| 124 // Get the function from the stack. | 124 // Get the function from the stack. |
| 125 __ movq(rcx, Operand(rsp, 1 * kPointerSize)); | 125 __ movq(rcx, Operand(rsp, 1 * kPointerSize)); |
| 126 | 126 |
| 127 // Setup the object header. | 127 // Setup the object header. |
| 128 __ LoadRoot(kScratchRegister, Heap::kContextMapRootIndex); | 128 __ LoadRoot(kScratchRegister, Heap::kFunctionContextMapRootIndex); |
| 129 __ movq(FieldOperand(rax, HeapObject::kMapOffset), kScratchRegister); | 129 __ movq(FieldOperand(rax, HeapObject::kMapOffset), kScratchRegister); |
| 130 __ Move(FieldOperand(rax, FixedArray::kLengthOffset), Smi::FromInt(length)); | 130 __ Move(FieldOperand(rax, FixedArray::kLengthOffset), Smi::FromInt(length)); |
| 131 | 131 |
| 132 // Setup the fixed slots. | 132 // Setup the fixed slots. |
| 133 __ Set(rbx, 0); // Set to NULL. | 133 __ Set(rbx, 0); // Set to NULL. |
| 134 __ movq(Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)), rcx); | 134 __ movq(Operand(rax, Context::SlotOffset(Context::CLOSURE_INDEX)), rcx); |
| 135 __ movq(Operand(rax, Context::SlotOffset(Context::FCONTEXT_INDEX)), rax); | 135 __ movq(Operand(rax, Context::SlotOffset(Context::PREVIOUS_INDEX)), rsi); |
| 136 __ movq(Operand(rax, Context::SlotOffset(Context::PREVIOUS_INDEX)), rbx); | |
| 137 __ movq(Operand(rax, Context::SlotOffset(Context::EXTENSION_INDEX)), rbx); | 136 __ movq(Operand(rax, Context::SlotOffset(Context::EXTENSION_INDEX)), rbx); |
| 138 | 137 |
| 139 // Copy the global object from the surrounding context. | 138 // Copy the global object from the previous context. |
| 140 __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 139 __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 141 __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_INDEX)), rbx); | 140 __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_INDEX)), rbx); |
| 142 | 141 |
| 143 // Initialize the rest of the slots to undefined. | 142 // Initialize the rest of the slots to undefined. |
| 144 __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); | 143 __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); |
| 145 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { | 144 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { |
| 146 __ movq(Operand(rax, Context::SlotOffset(i)), rbx); | 145 __ movq(Operand(rax, Context::SlotOffset(i)), rbx); |
| 147 } | 146 } |
| 148 | 147 |
| 149 // Return and remove the on-stack parameter. | 148 // Return and remove the on-stack parameter. |
| 150 __ movq(rsi, rax); | 149 __ movq(rsi, rax); |
| 151 __ ret(1 * kPointerSize); | 150 __ ret(1 * kPointerSize); |
| 152 | 151 |
| 153 // Need to collect. Call into runtime system. | 152 // Need to collect. Call into runtime system. |
| 154 __ bind(&gc); | 153 __ bind(&gc); |
| 155 __ TailCallRuntime(Runtime::kNewContext, 1, 1); | 154 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); |
| 156 } | 155 } |
| 157 | 156 |
| 158 | 157 |
| 159 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { | 158 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
| 160 // Stack layout on entry: | 159 // Stack layout on entry: |
| 161 // | 160 // |
| 162 // [rsp + kPointerSize]: constant elements. | 161 // [rsp + kPointerSize]: constant elements. |
| 163 // [rsp + (2 * kPointerSize)]: literal index. | 162 // [rsp + (2 * kPointerSize)]: literal index. |
| 164 // [rsp + (3 * kPointerSize)]: literals array. | 163 // [rsp + (3 * kPointerSize)]: literals array. |
| 165 | 164 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 } | 223 } |
| 225 | 224 |
| 226 // Return and remove the on-stack parameters. | 225 // Return and remove the on-stack parameters. |
| 227 __ ret(3 * kPointerSize); | 226 __ ret(3 * kPointerSize); |
| 228 | 227 |
| 229 __ bind(&slow_case); | 228 __ bind(&slow_case); |
| 230 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); | 229 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
| 231 } | 230 } |
| 232 | 231 |
| 233 | 232 |
| 233 // The stub returns zero for false, and a non-zero value for true. |
| 234 void ToBooleanStub::Generate(MacroAssembler* masm) { | 234 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 235 Label false_result, true_result, not_string; | 235 Label false_result, true_result, not_string; |
| 236 const Register map = rdx; |
| 237 |
| 236 __ movq(rax, Operand(rsp, 1 * kPointerSize)); | 238 __ movq(rax, Operand(rsp, 1 * kPointerSize)); |
| 237 | 239 |
| 238 // undefined -> false | 240 // undefined -> false |
| 239 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 241 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 240 __ j(equal, &false_result); | 242 __ j(equal, &false_result); |
| 241 | 243 |
| 242 // Boolean -> its value | 244 // Boolean -> its value |
| 243 __ CompareRoot(rax, Heap::kFalseValueRootIndex); | 245 __ CompareRoot(rax, Heap::kFalseValueRootIndex); |
| 244 __ j(equal, &false_result); | 246 __ j(equal, &false_result); |
| 245 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 247 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 246 __ j(equal, &true_result); | 248 __ j(equal, &true_result); |
| 247 | 249 |
| 248 // Smis: 0 -> false, all other -> true | 250 // Smis: 0 -> false, all other -> true |
| 249 __ Cmp(rax, Smi::FromInt(0)); | 251 __ Cmp(rax, Smi::FromInt(0)); |
| 250 __ j(equal, &false_result); | 252 __ j(equal, &false_result); |
| 251 Condition is_smi = __ CheckSmi(rax); | 253 __ JumpIfSmi(rax, &true_result); |
| 252 __ j(is_smi, &true_result); | |
| 253 | 254 |
| 254 // 'null' => false. | 255 // 'null' -> false. |
| 255 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 256 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 256 __ j(equal, &false_result, Label::kNear); | 257 __ j(equal, &false_result, Label::kNear); |
| 257 | 258 |
| 258 // Get the map and type of the heap object. | 259 // Get the map of the heap object. |
| 259 // We don't use CmpObjectType because we manipulate the type field. | 260 __ movq(map, FieldOperand(rax, HeapObject::kMapOffset)); |
| 260 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | |
| 261 __ movzxbq(rcx, FieldOperand(rdx, Map::kInstanceTypeOffset)); | |
| 262 | 261 |
| 263 // Undetectable => false. | 262 // Undetectable -> false. |
| 264 __ movzxbq(rbx, FieldOperand(rdx, Map::kBitFieldOffset)); | 263 __ testb(FieldOperand(map, Map::kBitFieldOffset), |
| 265 __ and_(rbx, Immediate(1 << Map::kIsUndetectable)); | 264 Immediate(1 << Map::kIsUndetectable)); |
| 266 __ j(not_zero, &false_result, Label::kNear); | 265 __ j(not_zero, &false_result, Label::kNear); |
| 267 | 266 |
| 268 // JavaScript object => true. | 267 // JavaScript object -> true. |
| 269 __ cmpq(rcx, Immediate(FIRST_JS_OBJECT_TYPE)); | 268 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
| 270 __ j(above_equal, &true_result, Label::kNear); | 269 __ j(above_equal, &true_result, Label::kNear); |
| 271 | 270 |
| 272 // String value => false iff empty. | 271 // String value -> false iff empty. |
| 273 __ cmpq(rcx, Immediate(FIRST_NONSTRING_TYPE)); | 272 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); |
| 274 __ j(above_equal, ¬_string, Label::kNear); | 273 __ j(above_equal, ¬_string, Label::kNear); |
| 275 __ movq(rdx, FieldOperand(rax, String::kLengthOffset)); | 274 __ cmpq(FieldOperand(rax, String::kLengthOffset), Immediate(0)); |
| 276 __ SmiTest(rdx); | |
| 277 __ j(zero, &false_result, Label::kNear); | 275 __ j(zero, &false_result, Label::kNear); |
| 278 __ jmp(&true_result, Label::kNear); | 276 __ jmp(&true_result, Label::kNear); |
| 279 | 277 |
| 280 __ bind(¬_string); | 278 __ bind(¬_string); |
| 281 __ CompareRoot(rdx, Heap::kHeapNumberMapRootIndex); | 279 // HeapNumber -> false iff +0, -0, or NaN. |
| 280 // These three cases set the zero flag when compared to zero using ucomisd. |
| 281 __ CompareRoot(map, Heap::kHeapNumberMapRootIndex); |
| 282 __ j(not_equal, &true_result, Label::kNear); | 282 __ j(not_equal, &true_result, Label::kNear); |
| 283 // HeapNumber => false iff +0, -0, or NaN. | |
| 284 // These three cases set the zero flag when compared to zero using ucomisd. | |
| 285 __ xorps(xmm0, xmm0); | 283 __ xorps(xmm0, xmm0); |
| 286 __ ucomisd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); | 284 __ ucomisd(xmm0, FieldOperand(rax, HeapNumber::kValueOffset)); |
| 287 __ j(zero, &false_result, Label::kNear); | 285 __ j(zero, &false_result, Label::kNear); |
| 288 // Fall through to |true_result|. | 286 // Fall through to |true_result|. |
| 289 | 287 |
| 290 // Return 1/0 for true/false in rax. | 288 // Return 1/0 for true/false in tos_. |
| 291 __ bind(&true_result); | 289 __ bind(&true_result); |
| 292 __ Set(rax, 1); | 290 __ Set(tos_, 1); |
| 293 __ ret(1 * kPointerSize); | 291 __ ret(1 * kPointerSize); |
| 294 __ bind(&false_result); | 292 __ bind(&false_result); |
| 295 __ Set(rax, 0); | 293 __ Set(tos_, 0); |
| 296 __ ret(1 * kPointerSize); | 294 __ ret(1 * kPointerSize); |
| 297 } | 295 } |
| 298 | 296 |
| 299 | 297 |
| 300 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { | 298 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { |
| 301 __ PushCallerSaved(save_doubles_); | 299 __ PushCallerSaved(save_doubles_); |
| 302 const int argument_count = 1; | 300 const int argument_count = 1; |
| 303 __ PrepareCallCFunction(argument_count); | 301 __ PrepareCallCFunction(argument_count); |
| 304 #ifdef _WIN64 | 302 #ifdef _WIN64 |
| 305 __ LoadAddress(rcx, ExternalReference::isolate_address()); | 303 __ LoadAddress(rcx, ExternalReference::isolate_address()); |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 416 // As the then-branch, but move double-value to result before shifting. | 414 // As the then-branch, but move double-value to result before shifting. |
| 417 __ xorl(result, double_value); | 415 __ xorl(result, double_value); |
| 418 __ leal(rcx, Operand(double_exponent, -HeapNumber::kMantissaBits - 1)); | 416 __ leal(rcx, Operand(double_exponent, -HeapNumber::kMantissaBits - 1)); |
| 419 __ shll_cl(result); | 417 __ shll_cl(result); |
| 420 } | 418 } |
| 421 | 419 |
| 422 __ bind(&done); | 420 __ bind(&done); |
| 423 } | 421 } |
| 424 | 422 |
| 425 | 423 |
| 426 Handle<Code> GetUnaryOpStub(int key, UnaryOpIC::TypeInfo type_info) { | |
| 427 UnaryOpStub stub(key, type_info); | |
| 428 return stub.GetCode(); | |
| 429 } | |
| 430 | |
| 431 | |
| 432 void UnaryOpStub::Generate(MacroAssembler* masm) { | 424 void UnaryOpStub::Generate(MacroAssembler* masm) { |
| 433 switch (operand_type_) { | 425 switch (operand_type_) { |
| 434 case UnaryOpIC::UNINITIALIZED: | 426 case UnaryOpIC::UNINITIALIZED: |
| 435 GenerateTypeTransition(masm); | 427 GenerateTypeTransition(masm); |
| 436 break; | 428 break; |
| 437 case UnaryOpIC::SMI: | 429 case UnaryOpIC::SMI: |
| 438 GenerateSmiStub(masm); | 430 GenerateSmiStub(masm); |
| 439 break; | 431 break; |
| 440 case UnaryOpIC::HEAP_NUMBER: | 432 case UnaryOpIC::HEAP_NUMBER: |
| 441 GenerateHeapNumberStub(masm); | 433 GenerateHeapNumberStub(masm); |
| 442 break; | 434 break; |
| 443 case UnaryOpIC::GENERIC: | 435 case UnaryOpIC::GENERIC: |
| 444 GenerateGenericStub(masm); | 436 GenerateGenericStub(masm); |
| 445 break; | 437 break; |
| 446 } | 438 } |
| 447 } | 439 } |
| 448 | 440 |
| 449 | 441 |
| 450 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 442 void UnaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 451 __ pop(rcx); // Save return address. | 443 __ pop(rcx); // Save return address. |
| 452 __ push(rax); | 444 |
| 453 // Left and right arguments are now on top. | 445 __ push(rax); // the operand |
| 454 // Push this stub's key. Although the operation and the type info are | |
| 455 // encoded into the key, the encoding is opaque, so push them too. | |
| 456 __ Push(Smi::FromInt(MinorKey())); | |
| 457 __ Push(Smi::FromInt(op_)); | 446 __ Push(Smi::FromInt(op_)); |
| 447 __ Push(Smi::FromInt(mode_)); |
| 458 __ Push(Smi::FromInt(operand_type_)); | 448 __ Push(Smi::FromInt(operand_type_)); |
| 459 | 449 |
| 460 __ push(rcx); // Push return address. | 450 __ push(rcx); // Push return address. |
| 461 | 451 |
| 462 // Patch the caller to an appropriate specialized stub and return the | 452 // Patch the caller to an appropriate specialized stub and return the |
| 463 // operation result to the caller of the stub. | 453 // operation result to the caller of the stub. |
| 464 __ TailCallExternalReference( | 454 __ TailCallExternalReference( |
| 465 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), | 455 ExternalReference(IC_Utility(IC::kUnaryOp_Patch), masm->isolate()), 4, 1); |
| 466 masm->isolate()), | |
| 467 4, | |
| 468 1); | |
| 469 } | 456 } |
| 470 | 457 |
| 471 | 458 |
| 472 // TODO(svenpanne): Use virtual functions instead of switch. | 459 // TODO(svenpanne): Use virtual functions instead of switch. |
| 473 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { | 460 void UnaryOpStub::GenerateSmiStub(MacroAssembler* masm) { |
| 474 switch (op_) { | 461 switch (op_) { |
| 475 case Token::SUB: | 462 case Token::SUB: |
| 476 GenerateSmiStubSub(masm); | 463 GenerateSmiStubSub(masm); |
| 477 break; | 464 break; |
| 478 case Token::BIT_NOT: | 465 case Token::BIT_NOT: |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 687 | 674 |
| 688 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 675 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
| 689 "UnaryOpStub_%s_%s_%s", | 676 "UnaryOpStub_%s_%s_%s", |
| 690 op_name, | 677 op_name, |
| 691 overwrite_name, | 678 overwrite_name, |
| 692 UnaryOpIC::GetName(operand_type_)); | 679 UnaryOpIC::GetName(operand_type_)); |
| 693 return name_; | 680 return name_; |
| 694 } | 681 } |
| 695 | 682 |
| 696 | 683 |
| 697 Handle<Code> GetBinaryOpStub(int key, | |
| 698 BinaryOpIC::TypeInfo type_info, | |
| 699 BinaryOpIC::TypeInfo result_type_info) { | |
| 700 BinaryOpStub stub(key, type_info, result_type_info); | |
| 701 return stub.GetCode(); | |
| 702 } | |
| 703 | |
| 704 | |
| 705 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { | 684 void BinaryOpStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 706 __ pop(rcx); // Save return address. | 685 __ pop(rcx); // Save return address. |
| 707 __ push(rdx); | 686 __ push(rdx); |
| 708 __ push(rax); | 687 __ push(rax); |
| 709 // Left and right arguments are now on top. | 688 // Left and right arguments are now on top. |
| 710 // Push this stub's key. Although the operation and the type info are | 689 // Push this stub's key. Although the operation and the type info are |
| 711 // encoded into the key, the encoding is opaque, so push them too. | 690 // encoded into the key, the encoding is opaque, so push them too. |
| 712 __ Push(Smi::FromInt(MinorKey())); | 691 __ Push(Smi::FromInt(MinorKey())); |
| 713 __ Push(Smi::FromInt(op_)); | 692 __ Push(Smi::FromInt(op_)); |
| 714 __ Push(Smi::FromInt(operands_type_)); | 693 __ Push(Smi::FromInt(operands_type_)); |
| (...skipping 1254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1969 // Slow-case: Handle non-smi or out-of-bounds access to arguments | 1948 // Slow-case: Handle non-smi or out-of-bounds access to arguments |
| 1970 // by calling the runtime system. | 1949 // by calling the runtime system. |
| 1971 __ bind(&slow); | 1950 __ bind(&slow); |
| 1972 __ pop(rbx); // Return address. | 1951 __ pop(rbx); // Return address. |
| 1973 __ push(rdx); | 1952 __ push(rdx); |
| 1974 __ push(rbx); | 1953 __ push(rbx); |
| 1975 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); | 1954 __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1); |
| 1976 } | 1955 } |
| 1977 | 1956 |
| 1978 | 1957 |
| 1979 void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) { | 1958 void ArgumentsAccessStub::GenerateNewNonStrictFast(MacroAssembler* masm) { |
| 1959 // Stack layout: |
| 1960 // rsp[0] : return address |
| 1961 // rsp[8] : number of parameters (tagged) |
| 1962 // rsp[16] : receiver displacement |
| 1963 // rsp[24] : function |
| 1964 // Registers used over the whole function: |
| 1965 // rbx: the mapped parameter count (untagged) |
| 1966 // rax: the allocated object (tagged). |
| 1967 |
| 1968 Factory* factory = masm->isolate()->factory(); |
| 1969 |
| 1970 __ SmiToInteger64(rbx, Operand(rsp, 1 * kPointerSize)); |
| 1971 // rbx = parameter count (untagged) |
| 1972 |
| 1973 // Check if the calling frame is an arguments adaptor frame. |
| 1974 Label runtime; |
| 1975 Label adaptor_frame, try_allocate; |
| 1976 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 1977 __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); |
| 1978 __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 1979 __ j(equal, &adaptor_frame); |
| 1980 |
| 1981 // No adaptor, parameter count = argument count. |
| 1982 __ movq(rcx, rbx); |
| 1983 __ jmp(&try_allocate, Label::kNear); |
| 1984 |
| 1985 // We have an adaptor frame. Patch the parameters pointer. |
| 1986 __ bind(&adaptor_frame); |
| 1987 __ SmiToInteger64(rcx, |
| 1988 Operand(rdx, |
| 1989 ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 1990 __ lea(rdx, Operand(rdx, rcx, times_pointer_size, |
| 1991 StandardFrameConstants::kCallerSPOffset)); |
| 1992 __ movq(Operand(rsp, 2 * kPointerSize), rdx); |
| 1993 |
| 1994 // rbx = parameter count (untagged) |
| 1995 // rcx = argument count (untagged) |
| 1996 // Compute the mapped parameter count = min(rbx, rcx) in rbx. |
| 1997 __ cmpq(rbx, rcx); |
| 1998 __ j(less_equal, &try_allocate, Label::kNear); |
| 1999 __ movq(rbx, rcx); |
| 2000 |
| 2001 __ bind(&try_allocate); |
| 2002 |
| 2003 // Compute the sizes of backing store, parameter map, and arguments object. |
| 2004 // 1. Parameter map, has 2 extra words containing context and backing store. |
| 2005 const int kParameterMapHeaderSize = |
| 2006 FixedArray::kHeaderSize + 2 * kPointerSize; |
| 2007 Label no_parameter_map; |
| 2008 __ testq(rbx, rbx); |
| 2009 __ j(zero, &no_parameter_map, Label::kNear); |
| 2010 __ lea(r8, Operand(rbx, times_pointer_size, kParameterMapHeaderSize)); |
| 2011 __ bind(&no_parameter_map); |
| 2012 |
| 2013 // 2. Backing store. |
| 2014 __ lea(r8, Operand(r8, rcx, times_pointer_size, FixedArray::kHeaderSize)); |
| 2015 |
| 2016 // 3. Arguments object. |
| 2017 __ addq(r8, Immediate(Heap::kArgumentsObjectSize)); |
| 2018 |
| 2019 // Do the allocation of all three objects in one go. |
| 2020 __ AllocateInNewSpace(r8, rax, rdx, rdi, &runtime, TAG_OBJECT); |
| 2021 |
| 2022 // rax = address of new object(s) (tagged) |
| 2023 // rcx = argument count (untagged) |
| 2024 // Get the arguments boilerplate from the current (global) context into rdi. |
| 2025 Label has_mapped_parameters, copy; |
| 2026 __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 2027 __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset)); |
| 2028 __ testq(rbx, rbx); |
| 2029 __ j(not_zero, &has_mapped_parameters, Label::kNear); |
| 2030 |
| 2031 const int kIndex = Context::ARGUMENTS_BOILERPLATE_INDEX; |
| 2032 __ movq(rdi, Operand(rdi, Context::SlotOffset(kIndex))); |
| 2033 __ jmp(©, Label::kNear); |
| 2034 |
| 2035 const int kAliasedIndex = Context::ALIASED_ARGUMENTS_BOILERPLATE_INDEX; |
| 2036 __ bind(&has_mapped_parameters); |
| 2037 __ movq(rdi, Operand(rdi, Context::SlotOffset(kAliasedIndex))); |
| 2038 __ bind(©); |
| 2039 |
| 2040 // rax = address of new object (tagged) |
| 2041 // rbx = mapped parameter count (untagged) |
| 2042 // rcx = argument count (untagged) |
| 2043 // rdi = address of boilerplate object (tagged) |
| 2044 // Copy the JS object part. |
| 2045 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |
| 2046 __ movq(rdx, FieldOperand(rdi, i)); |
| 2047 __ movq(FieldOperand(rax, i), rdx); |
| 2048 } |
| 2049 |
| 2050 // Setup the callee in-object property. |
| 2051 STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1); |
| 2052 __ movq(rdx, Operand(rsp, 3 * kPointerSize)); |
| 2053 __ movq(FieldOperand(rax, JSObject::kHeaderSize + |
| 2054 Heap::kArgumentsCalleeIndex * kPointerSize), |
| 2055 rdx); |
| 2056 |
| 2057 // Use the length (smi tagged) and set that as an in-object property too. |
| 2058 // Note: rcx is tagged from here on. |
| 2059 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); |
| 2060 __ Integer32ToSmi(rcx, rcx); |
| 2061 __ movq(FieldOperand(rax, JSObject::kHeaderSize + |
| 2062 Heap::kArgumentsLengthIndex * kPointerSize), |
| 2063 rcx); |
| 2064 |
| 2065 // Setup the elements pointer in the allocated arguments object. |
| 2066 // If we allocated a parameter map, edi will point there, otherwise to the |
| 2067 // backing store. |
| 2068 __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSize)); |
| 2069 __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi); |
| 2070 |
| 2071 // rax = address of new object (tagged) |
| 2072 // rbx = mapped parameter count (untagged) |
| 2073 // rcx = argument count (tagged) |
| 2074 // rdi = address of parameter map or backing store (tagged) |
| 2075 |
| 2076 // Initialize parameter map. If there are no mapped arguments, we're done. |
| 2077 Label skip_parameter_map; |
| 2078 __ testq(rbx, rbx); |
| 2079 __ j(zero, &skip_parameter_map); |
| 2080 |
| 2081 __ LoadRoot(kScratchRegister, Heap::kNonStrictArgumentsElementsMapRootIndex); |
| 2082 // rbx contains the untagged argument count. Add 2 and tag to write. |
| 2083 __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister); |
| 2084 __ Integer64PlusConstantToSmi(r9, rbx, 2); |
| 2085 __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), r9); |
| 2086 __ movq(FieldOperand(rdi, FixedArray::kHeaderSize + 0 * kPointerSize), rsi); |
| 2087 __ lea(r9, Operand(rdi, rbx, times_pointer_size, kParameterMapHeaderSize)); |
| 2088 __ movq(FieldOperand(rdi, FixedArray::kHeaderSize + 1 * kPointerSize), r9); |
| 2089 |
| 2090 // Copy the parameter slots and the holes in the arguments. |
| 2091 // We need to fill in mapped_parameter_count slots. They index the context, |
| 2092 // where parameters are stored in reverse order, at |
| 2093 // MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS+parameter_count-1 |
| 2094 // The mapped parameter thus need to get indices |
| 2095 // MIN_CONTEXT_SLOTS+parameter_count-1 .. |
| 2096 // MIN_CONTEXT_SLOTS+parameter_count-mapped_parameter_count |
| 2097 // We loop from right to left. |
| 2098 Label parameters_loop, parameters_test; |
| 2099 |
| 2100 // Load tagged parameter count into r9. |
| 2101 __ movq(r9, Operand(rsp, 1 * kPointerSize)); |
| 2102 __ Move(r8, Smi::FromInt(Context::MIN_CONTEXT_SLOTS)); |
| 2103 __ addq(r8, Operand(rsp, 3 * kPointerSize)); |
| 2104 __ subq(r8, r9); |
| 2105 __ Move(r11, factory->the_hole_value()); |
| 2106 __ movq(rdx, rdi); |
| 2107 __ SmiToInteger64(kScratchRegister, r9); |
| 2108 __ lea(rdi, Operand(rdi, kScratchRegister, |
| 2109 times_pointer_size, |
| 2110 kParameterMapHeaderSize)); |
| 2111 // r9 = loop variable (tagged) |
| 2112 // r8 = mapping index (tagged) |
| 2113 // r11 = the hole value |
| 2114 // rdx = address of parameter map (tagged) |
| 2115 // rdi = address of backing store (tagged) |
| 2116 __ jmp(¶meters_test, Label::kNear); |
| 2117 |
| 2118 __ bind(¶meters_loop); |
| 2119 __ SmiSubConstant(r9, r9, Smi::FromInt(1)); |
| 2120 __ SmiToInteger64(kScratchRegister, r9); |
| 2121 __ movq(FieldOperand(rdx, kScratchRegister, |
| 2122 times_pointer_size, |
| 2123 kParameterMapHeaderSize), |
| 2124 r8); |
| 2125 __ movq(FieldOperand(rdi, kScratchRegister, |
| 2126 times_pointer_size, |
| 2127 FixedArray::kHeaderSize), |
| 2128 r11); |
| 2129 __ SmiAddConstant(r8, r8, Smi::FromInt(1)); |
| 2130 __ bind(¶meters_test); |
| 2131 __ SmiTest(r9); |
| 2132 __ j(not_zero, ¶meters_loop, Label::kNear); |
| 2133 |
| 2134 __ bind(&skip_parameter_map); |
| 2135 |
| 2136 // rcx = argument count (tagged) |
| 2137 // rdi = address of backing store (tagged) |
| 2138 // Copy arguments header and remaining slots (if there are any). |
| 2139 __ Move(FieldOperand(rdi, FixedArray::kMapOffset), |
| 2140 factory->fixed_array_map()); |
| 2141 __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx); |
| 2142 |
| 2143 Label arguments_loop, arguments_test; |
| 2144 __ movq(r8, rbx); |
| 2145 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); |
| 2146 // Untag rcx and r8 for the loop below. |
| 2147 __ SmiToInteger64(rcx, rcx); |
| 2148 __ SmiToInteger64(r8, r8); |
| 2149 __ lea(kScratchRegister, Operand(r8, times_pointer_size, 0)); |
| 2150 __ subq(rdx, kScratchRegister); |
| 2151 __ jmp(&arguments_test, Label::kNear); |
| 2152 |
| 2153 __ bind(&arguments_loop); |
| 2154 __ subq(rdx, Immediate(kPointerSize)); |
| 2155 __ movq(r9, Operand(rdx, 0)); |
| 2156 __ movq(FieldOperand(rdi, r8, |
| 2157 times_pointer_size, |
| 2158 FixedArray::kHeaderSize), |
| 2159 r9); |
| 2160 __ addq(r8, Immediate(1)); |
| 2161 |
| 2162 __ bind(&arguments_test); |
| 2163 __ cmpq(r8, rcx); |
| 2164 __ j(less, &arguments_loop, Label::kNear); |
| 2165 |
| 2166 // Return and remove the on-stack parameters. |
| 2167 __ ret(3 * kPointerSize); |
| 2168 |
| 2169 // Do the runtime call to allocate the arguments object. |
| 2170 // rcx = argument count (untagged) |
| 2171 __ bind(&runtime); |
| 2172 __ Integer32ToSmi(rcx, rcx); |
| 2173 __ movq(Operand(rsp, 1 * kPointerSize), rcx); // Patch argument count. |
| 2174 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); |
| 2175 } |
| 2176 |
| 2177 |
| 2178 void ArgumentsAccessStub::GenerateNewNonStrictSlow(MacroAssembler* masm) { |
| 2179 // esp[0] : return address |
| 2180 // esp[8] : number of parameters |
| 2181 // esp[16] : receiver displacement |
| 2182 // esp[24] : function |
| 2183 |
| 2184 // Check if the calling frame is an arguments adaptor frame. |
| 2185 Label runtime; |
| 2186 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 2187 __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); |
| 2188 __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2189 __ j(not_equal, &runtime); |
| 2190 |
| 2191 // Patch the arguments.length and the parameters pointer. |
| 2192 __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2193 __ movq(Operand(rsp, 1 * kPointerSize), rcx); |
| 2194 __ SmiToInteger64(rcx, rcx); |
| 2195 __ lea(rdx, Operand(rdx, rcx, times_pointer_size, |
| 2196 StandardFrameConstants::kCallerSPOffset)); |
| 2197 __ movq(Operand(rsp, 2 * kPointerSize), rdx); |
| 2198 |
| 2199 __ bind(&runtime); |
| 2200 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); |
| 2201 } |
| 2202 |
| 2203 |
| 2204 void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) { |
| 1980 // rsp[0] : return address | 2205 // rsp[0] : return address |
| 1981 // rsp[8] : number of parameters | 2206 // rsp[8] : number of parameters |
| 1982 // rsp[16] : receiver displacement | 2207 // rsp[16] : receiver displacement |
| 1983 // rsp[24] : function | 2208 // rsp[24] : function |
| 1984 | 2209 |
| 1985 // The displacement is used for skipping the return address and the | |
| 1986 // frame pointer on the stack. It is the offset of the last | |
| 1987 // parameter (if any) relative to the frame pointer. | |
| 1988 static const int kDisplacement = 2 * kPointerSize; | |
| 1989 | |
| 1990 // Check if the calling frame is an arguments adaptor frame. | 2210 // Check if the calling frame is an arguments adaptor frame. |
| 1991 Label adaptor_frame, try_allocate, runtime; | 2211 Label adaptor_frame, try_allocate, runtime; |
| 1992 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 2212 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 1993 __ Cmp(Operand(rdx, StandardFrameConstants::kContextOffset), | 2213 __ movq(rcx, Operand(rdx, StandardFrameConstants::kContextOffset)); |
| 1994 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2214 __ Cmp(rcx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 1995 __ j(equal, &adaptor_frame); | 2215 __ j(equal, &adaptor_frame); |
| 1996 | 2216 |
| 1997 // Get the length from the frame. | 2217 // Get the length from the frame. |
| 1998 __ SmiToInteger32(rcx, Operand(rsp, 1 * kPointerSize)); | 2218 __ movq(rcx, Operand(rsp, 1 * kPointerSize)); |
| 2219 __ SmiToInteger64(rcx, rcx); |
| 1999 __ jmp(&try_allocate); | 2220 __ jmp(&try_allocate); |
| 2000 | 2221 |
| 2001 // Patch the arguments.length and the parameters pointer. | 2222 // Patch the arguments.length and the parameters pointer. |
| 2002 __ bind(&adaptor_frame); | 2223 __ bind(&adaptor_frame); |
| 2003 __ SmiToInteger32(rcx, | 2224 __ movq(rcx, Operand(rdx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2004 Operand(rdx, | 2225 __ movq(Operand(rsp, 1 * kPointerSize), rcx); |
| 2005 ArgumentsAdaptorFrameConstants::kLengthOffset)); | 2226 __ SmiToInteger64(rcx, rcx); |
| 2006 // Space on stack must already hold a smi. | 2227 __ lea(rdx, Operand(rdx, rcx, times_pointer_size, |
| 2007 __ Integer32ToSmiField(Operand(rsp, 1 * kPointerSize), rcx); | 2228 StandardFrameConstants::kCallerSPOffset)); |
| 2008 // Do not clobber the length index for the indexing operation since | |
| 2009 // it is used compute the size for allocation later. | |
| 2010 __ lea(rdx, Operand(rdx, rcx, times_pointer_size, kDisplacement)); | |
| 2011 __ movq(Operand(rsp, 2 * kPointerSize), rdx); | 2229 __ movq(Operand(rsp, 2 * kPointerSize), rdx); |
| 2012 | 2230 |
| 2013 // Try the new space allocation. Start out with computing the size of | 2231 // Try the new space allocation. Start out with computing the size of |
| 2014 // the arguments object and the elements array. | 2232 // the arguments object and the elements array. |
| 2015 Label add_arguments_object; | 2233 Label add_arguments_object; |
| 2016 __ bind(&try_allocate); | 2234 __ bind(&try_allocate); |
| 2017 __ testl(rcx, rcx); | 2235 __ testq(rcx, rcx); |
| 2018 __ j(zero, &add_arguments_object); | 2236 __ j(zero, &add_arguments_object, Label::kNear); |
| 2019 __ leal(rcx, Operand(rcx, times_pointer_size, FixedArray::kHeaderSize)); | 2237 __ lea(rcx, Operand(rcx, times_pointer_size, FixedArray::kHeaderSize)); |
| 2020 __ bind(&add_arguments_object); | 2238 __ bind(&add_arguments_object); |
| 2021 __ addl(rcx, Immediate(GetArgumentsObjectSize())); | 2239 __ addq(rcx, Immediate(Heap::kArgumentsObjectSizeStrict)); |
| 2022 | 2240 |
| 2023 // Do the allocation of both objects in one go. | 2241 // Do the allocation of both objects in one go. |
| 2024 __ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT); | 2242 __ AllocateInNewSpace(rcx, rax, rdx, rbx, &runtime, TAG_OBJECT); |
| 2025 | 2243 |
| 2026 // Get the arguments boilerplate from the current (global) context. | 2244 // Get the arguments boilerplate from the current (global) context. |
| 2027 __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); | 2245 __ movq(rdi, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); |
| 2028 __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset)); | 2246 __ movq(rdi, FieldOperand(rdi, GlobalObject::kGlobalContextOffset)); |
| 2029 __ movq(rdi, Operand(rdi, | 2247 const int offset = |
| 2030 Context::SlotOffset(GetArgumentsBoilerplateIndex()))); | 2248 Context::SlotOffset(Context::STRICT_MODE_ARGUMENTS_BOILERPLATE_INDEX); |
| 2249 __ movq(rdi, Operand(rdi, offset)); |
| 2031 | 2250 |
| 2032 // Copy the JS object part. | 2251 // Copy the JS object part. |
| 2033 STATIC_ASSERT(JSObject::kHeaderSize == 3 * kPointerSize); | 2252 for (int i = 0; i < JSObject::kHeaderSize; i += kPointerSize) { |
| 2034 __ movq(kScratchRegister, FieldOperand(rdi, 0 * kPointerSize)); | 2253 __ movq(rbx, FieldOperand(rdi, i)); |
| 2035 __ movq(rdx, FieldOperand(rdi, 1 * kPointerSize)); | 2254 __ movq(FieldOperand(rax, i), rbx); |
| 2036 __ movq(rbx, FieldOperand(rdi, 2 * kPointerSize)); | |
| 2037 __ movq(FieldOperand(rax, 0 * kPointerSize), kScratchRegister); | |
| 2038 __ movq(FieldOperand(rax, 1 * kPointerSize), rdx); | |
| 2039 __ movq(FieldOperand(rax, 2 * kPointerSize), rbx); | |
| 2040 | |
| 2041 if (type_ == NEW_NON_STRICT) { | |
| 2042 // Setup the callee in-object property. | |
| 2043 ASSERT(Heap::kArgumentsCalleeIndex == 1); | |
| 2044 __ movq(kScratchRegister, Operand(rsp, 3 * kPointerSize)); | |
| 2045 __ movq(FieldOperand(rax, JSObject::kHeaderSize + | |
| 2046 Heap::kArgumentsCalleeIndex * kPointerSize), | |
| 2047 kScratchRegister); | |
| 2048 } | 2255 } |
| 2049 | 2256 |
| 2050 // Get the length (smi tagged) and set that as an in-object property too. | 2257 // Get the length (smi tagged) and set that as an in-object property too. |
| 2051 ASSERT(Heap::kArgumentsLengthIndex == 0); | 2258 STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0); |
| 2052 __ movq(rcx, Operand(rsp, 1 * kPointerSize)); | 2259 __ movq(rcx, Operand(rsp, 1 * kPointerSize)); |
| 2053 __ movq(FieldOperand(rax, JSObject::kHeaderSize + | 2260 __ movq(FieldOperand(rax, JSObject::kHeaderSize + |
| 2054 Heap::kArgumentsLengthIndex * kPointerSize), | 2261 Heap::kArgumentsLengthIndex * kPointerSize), |
| 2055 rcx); | 2262 rcx); |
| 2056 | 2263 |
| 2057 // If there are no actual arguments, we're done. | 2264 // If there are no actual arguments, we're done. |
| 2058 Label done; | 2265 Label done; |
| 2059 __ SmiTest(rcx); | 2266 __ testq(rcx, rcx); |
| 2060 __ j(zero, &done); | 2267 __ j(zero, &done); |
| 2061 | 2268 |
| 2062 // Get the parameters pointer from the stack and untag the length. | 2269 // Get the parameters pointer from the stack. |
| 2063 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); | 2270 __ movq(rdx, Operand(rsp, 2 * kPointerSize)); |
| 2064 | 2271 |
| 2065 // Setup the elements pointer in the allocated arguments object and | 2272 // Setup the elements pointer in the allocated arguments object and |
| 2066 // initialize the header in the elements fixed array. | 2273 // initialize the header in the elements fixed array. |
| 2067 __ lea(rdi, Operand(rax, GetArgumentsObjectSize())); | 2274 __ lea(rdi, Operand(rax, Heap::kArgumentsObjectSizeStrict)); |
| 2068 __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi); | 2275 __ movq(FieldOperand(rax, JSObject::kElementsOffset), rdi); |
| 2069 __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex); | 2276 __ LoadRoot(kScratchRegister, Heap::kFixedArrayMapRootIndex); |
| 2070 __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister); | 2277 __ movq(FieldOperand(rdi, FixedArray::kMapOffset), kScratchRegister); |
| 2278 |
| 2279 |
| 2071 __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx); | 2280 __ movq(FieldOperand(rdi, FixedArray::kLengthOffset), rcx); |
| 2072 __ SmiToInteger32(rcx, rcx); // Untag length for the loop below. | 2281 // Untag the length for the loop below. |
| 2282 __ SmiToInteger64(rcx, rcx); |
| 2073 | 2283 |
| 2074 // Copy the fixed array slots. | 2284 // Copy the fixed array slots. |
| 2075 Label loop; | 2285 Label loop; |
| 2076 __ bind(&loop); | 2286 __ bind(&loop); |
| 2077 __ movq(kScratchRegister, Operand(rdx, -1 * kPointerSize)); // Skip receiver. | 2287 __ movq(rbx, Operand(rdx, -1 * kPointerSize)); // Skip receiver. |
| 2078 __ movq(FieldOperand(rdi, FixedArray::kHeaderSize), kScratchRegister); | 2288 __ movq(FieldOperand(rdi, FixedArray::kHeaderSize), rbx); |
| 2079 __ addq(rdi, Immediate(kPointerSize)); | 2289 __ addq(rdi, Immediate(kPointerSize)); |
| 2080 __ subq(rdx, Immediate(kPointerSize)); | 2290 __ subq(rdx, Immediate(kPointerSize)); |
| 2081 __ decl(rcx); | 2291 __ decq(rcx); |
| 2082 __ j(not_zero, &loop); | 2292 __ j(not_zero, &loop); |
| 2083 | 2293 |
| 2084 // Return and remove the on-stack parameters. | 2294 // Return and remove the on-stack parameters. |
| 2085 __ bind(&done); | 2295 __ bind(&done); |
| 2086 __ ret(3 * kPointerSize); | 2296 __ ret(3 * kPointerSize); |
| 2087 | 2297 |
| 2088 // Do the runtime call to allocate the arguments object. | 2298 // Do the runtime call to allocate the arguments object. |
| 2089 __ bind(&runtime); | 2299 __ bind(&runtime); |
| 2090 __ TailCallRuntime(Runtime::kNewArgumentsFast, 3, 1); | 2300 __ TailCallRuntime(Runtime::kNewStrictArgumentsFast, 3, 1); |
| 2091 } | 2301 } |
| 2092 | 2302 |
| 2093 | 2303 |
| 2094 void RegExpExecStub::Generate(MacroAssembler* masm) { | 2304 void RegExpExecStub::Generate(MacroAssembler* masm) { |
| 2095 // Just jump directly to runtime if native RegExp is not selected at compile | 2305 // Just jump directly to runtime if native RegExp is not selected at compile |
| 2096 // time or if regexp entry in generated code is turned off runtime switch or | 2306 // time or if regexp entry in generated code is turned off runtime switch or |
| 2097 // at compilation. | 2307 // at compilation. |
| 2098 #ifdef V8_INTERPRETED_REGEXP | 2308 #ifdef V8_INTERPRETED_REGEXP |
| 2099 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); | 2309 __ TailCallRuntime(Runtime::kRegExpExec, 4, 1); |
| 2100 #else // V8_INTERPRETED_REGEXP | 2310 #else // V8_INTERPRETED_REGEXP |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2249 | 2459 |
| 2250 __ bind(&seq_two_byte_string); | 2460 __ bind(&seq_two_byte_string); |
| 2251 // rdi: subject string (flat two-byte) | 2461 // rdi: subject string (flat two-byte) |
| 2252 // rax: RegExp data (FixedArray) | 2462 // rax: RegExp data (FixedArray) |
| 2253 __ movq(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); | 2463 __ movq(r11, FieldOperand(rax, JSRegExp::kDataUC16CodeOffset)); |
| 2254 __ Set(rcx, 0); // Type is two byte. | 2464 __ Set(rcx, 0); // Type is two byte. |
| 2255 | 2465 |
| 2256 __ bind(&check_code); | 2466 __ bind(&check_code); |
| 2257 // Check that the irregexp code has been generated for the actual string | 2467 // Check that the irregexp code has been generated for the actual string |
| 2258 // encoding. If it has, the field contains a code object otherwise it contains | 2468 // encoding. If it has, the field contains a code object otherwise it contains |
| 2259 // the hole. | 2469 // smi (code flushing support) |
| 2260 __ CmpObjectType(r11, CODE_TYPE, kScratchRegister); | 2470 __ JumpIfSmi(r11, &runtime); |
| 2261 __ j(not_equal, &runtime); | |
| 2262 | 2471 |
| 2263 // rdi: subject string | 2472 // rdi: subject string |
| 2264 // rcx: encoding of subject string (1 if ascii, 0 if two_byte); | 2473 // rcx: encoding of subject string (1 if ascii, 0 if two_byte); |
| 2265 // r11: code | 2474 // r11: code |
| 2266 // Load used arguments before starting to push arguments for call to native | 2475 // Load used arguments before starting to push arguments for call to native |
| 2267 // RegExp code to avoid handling changing stack height. | 2476 // RegExp code to avoid handling changing stack height. |
| 2268 __ SmiToInteger64(rbx, Operand(rsp, kPreviousIndexOffset)); | 2477 __ SmiToInteger64(rbx, Operand(rsp, kPreviousIndexOffset)); |
| 2269 | 2478 |
| 2270 // rdi: subject string | 2479 // rdi: subject string |
| 2271 // rbx: previous index | 2480 // rbx: previous index |
| (...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2728 if (never_nan_nan_ && (cc_ == equal)) { | 2937 if (never_nan_nan_ && (cc_ == equal)) { |
| 2729 __ Set(rax, EQUAL); | 2938 __ Set(rax, EQUAL); |
| 2730 __ ret(0); | 2939 __ ret(0); |
| 2731 } else { | 2940 } else { |
| 2732 Label heap_number; | 2941 Label heap_number; |
| 2733 // If it's not a heap number, then return equal for (in)equality operator. | 2942 // If it's not a heap number, then return equal for (in)equality operator. |
| 2734 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), | 2943 __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset), |
| 2735 factory->heap_number_map()); | 2944 factory->heap_number_map()); |
| 2736 __ j(equal, &heap_number, Label::kNear); | 2945 __ j(equal, &heap_number, Label::kNear); |
| 2737 if (cc_ != equal) { | 2946 if (cc_ != equal) { |
| 2738 // Call runtime on identical JSObjects. Otherwise return equal. | 2947 // Call runtime on identical objects. Otherwise return equal. |
| 2739 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); | 2948 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); |
| 2740 __ j(above_equal, ¬_identical, Label::kNear); | 2949 __ j(above_equal, ¬_identical, Label::kNear); |
| 2741 } | 2950 } |
| 2742 __ Set(rax, EQUAL); | 2951 __ Set(rax, EQUAL); |
| 2743 __ ret(0); | 2952 __ ret(0); |
| 2744 | 2953 |
| 2745 __ bind(&heap_number); | 2954 __ bind(&heap_number); |
| 2746 // It is a heap number, so return equal if it's not NaN. | 2955 // It is a heap number, so return equal if it's not NaN. |
| 2747 // For NaN, return 1 for every condition except greater and | 2956 // For NaN, return 1 for every condition except greater and |
| 2748 // greater-equal. Return -1 for them, so the comparison yields | 2957 // greater-equal. Return -1 for them, so the comparison yields |
| 2749 // false for all conditions except not-equal. | 2958 // false for all conditions except not-equal. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2785 __ ret(0); | 2994 __ ret(0); |
| 2786 | 2995 |
| 2787 __ bind(¬_smis); | 2996 __ bind(¬_smis); |
| 2788 } | 2997 } |
| 2789 | 2998 |
| 2790 // If either operand is a JSObject or an oddball value, then they are not | 2999 // If either operand is a JSObject or an oddball value, then they are not |
| 2791 // equal since their pointers are different | 3000 // equal since their pointers are different |
| 2792 // There is no test for undetectability in strict equality. | 3001 // There is no test for undetectability in strict equality. |
| 2793 | 3002 |
| 2794 // If the first object is a JS object, we have done pointer comparison. | 3003 // If the first object is a JS object, we have done pointer comparison. |
| 2795 STATIC_ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); | 3004 STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE); |
| 2796 Label first_non_object; | 3005 Label first_non_object; |
| 2797 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); | 3006 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rcx); |
| 2798 __ j(below, &first_non_object, Label::kNear); | 3007 __ j(below, &first_non_object, Label::kNear); |
| 2799 // Return non-zero (eax (not rax) is not zero) | 3008 // Return non-zero (eax (not rax) is not zero) |
| 2800 Label return_not_equal; | 3009 Label return_not_equal; |
| 2801 STATIC_ASSERT(kHeapObjectTag != 0); | 3010 STATIC_ASSERT(kHeapObjectTag != 0); |
| 2802 __ bind(&return_not_equal); | 3011 __ bind(&return_not_equal); |
| 2803 __ ret(0); | 3012 __ ret(0); |
| 2804 | 3013 |
| 2805 __ bind(&first_non_object); | 3014 __ bind(&first_non_object); |
| 2806 // Check for oddballs: true, false, null, undefined. | 3015 // Check for oddballs: true, false, null, undefined. |
| 2807 __ CmpInstanceType(rcx, ODDBALL_TYPE); | 3016 __ CmpInstanceType(rcx, ODDBALL_TYPE); |
| 2808 __ j(equal, &return_not_equal); | 3017 __ j(equal, &return_not_equal); |
| 2809 | 3018 |
| 2810 __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); | 3019 __ CmpObjectType(rdx, FIRST_SPEC_OBJECT_TYPE, rcx); |
| 2811 __ j(above_equal, &return_not_equal); | 3020 __ j(above_equal, &return_not_equal); |
| 2812 | 3021 |
| 2813 // Check for oddballs: true, false, null, undefined. | 3022 // Check for oddballs: true, false, null, undefined. |
| 2814 __ CmpInstanceType(rcx, ODDBALL_TYPE); | 3023 __ CmpInstanceType(rcx, ODDBALL_TYPE); |
| 2815 __ j(equal, &return_not_equal); | 3024 __ j(equal, &return_not_equal); |
| 2816 | 3025 |
| 2817 // Fall through to the general case. | 3026 // Fall through to the general case. |
| 2818 } | 3027 } |
| 2819 __ bind(&slow); | 3028 __ bind(&slow); |
| 2820 } | 3029 } |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2896 // and their pointers are different. | 3105 // and their pointers are different. |
| 2897 Label not_both_objects, return_unequal; | 3106 Label not_both_objects, return_unequal; |
| 2898 // At most one is a smi, so we can test for smi by adding the two. | 3107 // At most one is a smi, so we can test for smi by adding the two. |
| 2899 // A smi plus a heap object has the low bit set, a heap object plus | 3108 // A smi plus a heap object has the low bit set, a heap object plus |
| 2900 // a heap object has the low bit clear. | 3109 // a heap object has the low bit clear. |
| 2901 STATIC_ASSERT(kSmiTag == 0); | 3110 STATIC_ASSERT(kSmiTag == 0); |
| 2902 STATIC_ASSERT(kSmiTagMask == 1); | 3111 STATIC_ASSERT(kSmiTagMask == 1); |
| 2903 __ lea(rcx, Operand(rax, rdx, times_1, 0)); | 3112 __ lea(rcx, Operand(rax, rdx, times_1, 0)); |
| 2904 __ testb(rcx, Immediate(kSmiTagMask)); | 3113 __ testb(rcx, Immediate(kSmiTagMask)); |
| 2905 __ j(not_zero, ¬_both_objects, Label::kNear); | 3114 __ j(not_zero, ¬_both_objects, Label::kNear); |
| 2906 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx); | 3115 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rbx); |
| 2907 __ j(below, ¬_both_objects, Label::kNear); | 3116 __ j(below, ¬_both_objects, Label::kNear); |
| 2908 __ CmpObjectType(rdx, FIRST_JS_OBJECT_TYPE, rcx); | 3117 __ CmpObjectType(rdx, FIRST_SPEC_OBJECT_TYPE, rcx); |
| 2909 __ j(below, ¬_both_objects, Label::kNear); | 3118 __ j(below, ¬_both_objects, Label::kNear); |
| 2910 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), | 3119 __ testb(FieldOperand(rbx, Map::kBitFieldOffset), |
| 2911 Immediate(1 << Map::kIsUndetectable)); | 3120 Immediate(1 << Map::kIsUndetectable)); |
| 2912 __ j(zero, &return_unequal, Label::kNear); | 3121 __ j(zero, &return_unequal, Label::kNear); |
| 2913 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), | 3122 __ testb(FieldOperand(rcx, Map::kBitFieldOffset), |
| 2914 Immediate(1 << Map::kIsUndetectable)); | 3123 Immediate(1 << Map::kIsUndetectable)); |
| 2915 __ j(zero, &return_unequal, Label::kNear); | 3124 __ j(zero, &return_unequal, Label::kNear); |
| 2916 // The objects are both undetectable, so they both compare as the value | 3125 // The objects are both undetectable, so they both compare as the value |
| 2917 // undefined, and are equal. | 3126 // undefined, and are equal. |
| 2918 __ Set(rax, EQUAL); | 3127 __ Set(rax, EQUAL); |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2998 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | 3207 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
| 2999 __ j(not_equal, &slow); | 3208 __ j(not_equal, &slow); |
| 3000 | 3209 |
| 3001 // Fast-case: Just invoke the function. | 3210 // Fast-case: Just invoke the function. |
| 3002 ParameterCount actual(argc_); | 3211 ParameterCount actual(argc_); |
| 3003 | 3212 |
| 3004 if (ReceiverMightBeImplicit()) { | 3213 if (ReceiverMightBeImplicit()) { |
| 3005 Label call_as_function; | 3214 Label call_as_function; |
| 3006 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); | 3215 __ CompareRoot(rax, Heap::kTheHoleValueRootIndex); |
| 3007 __ j(equal, &call_as_function); | 3216 __ j(equal, &call_as_function); |
| 3008 __ InvokeFunction(rdi, actual, JUMP_FUNCTION); | 3217 __ InvokeFunction(rdi, |
| 3218 actual, |
| 3219 JUMP_FUNCTION, |
| 3220 NullCallWrapper(), |
| 3221 CALL_AS_METHOD); |
| 3009 __ bind(&call_as_function); | 3222 __ bind(&call_as_function); |
| 3010 } | 3223 } |
| 3011 __ InvokeFunction(rdi, | 3224 __ InvokeFunction(rdi, |
| 3012 actual, | 3225 actual, |
| 3013 JUMP_FUNCTION, | 3226 JUMP_FUNCTION, |
| 3014 NullCallWrapper(), | 3227 NullCallWrapper(), |
| 3015 CALL_AS_FUNCTION); | 3228 CALL_AS_FUNCTION); |
| 3016 | 3229 |
| 3017 // Slow-case: Non-function called. | 3230 // Slow-case: Non-function called. |
| 3018 __ bind(&slow); | 3231 __ bind(&slow); |
| (...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3430 ASSERT(flags_ == kNoFlags || HasCallSiteInlineCheck()); | 3643 ASSERT(flags_ == kNoFlags || HasCallSiteInlineCheck()); |
| 3431 int extra_stack_space = HasCallSiteInlineCheck() ? kPointerSize : 0; | 3644 int extra_stack_space = HasCallSiteInlineCheck() ? kPointerSize : 0; |
| 3432 | 3645 |
| 3433 // Get the object - go slow case if it's a smi. | 3646 // Get the object - go slow case if it's a smi. |
| 3434 Label slow; | 3647 Label slow; |
| 3435 | 3648 |
| 3436 __ movq(rax, Operand(rsp, 2 * kPointerSize + extra_stack_space)); | 3649 __ movq(rax, Operand(rsp, 2 * kPointerSize + extra_stack_space)); |
| 3437 __ JumpIfSmi(rax, &slow); | 3650 __ JumpIfSmi(rax, &slow); |
| 3438 | 3651 |
| 3439 // Check that the left hand is a JS object. Leave its map in rax. | 3652 // Check that the left hand is a JS object. Leave its map in rax. |
| 3440 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rax); | 3653 __ CmpObjectType(rax, FIRST_SPEC_OBJECT_TYPE, rax); |
| 3441 __ j(below, &slow); | 3654 __ j(below, &slow); |
| 3442 __ CmpInstanceType(rax, LAST_JS_OBJECT_TYPE); | 3655 __ CmpInstanceType(rax, LAST_SPEC_OBJECT_TYPE); |
| 3443 __ j(above, &slow); | 3656 __ j(above, &slow); |
| 3444 | 3657 |
| 3445 // Get the prototype of the function. | 3658 // Get the prototype of the function. |
| 3446 __ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space)); | 3659 __ movq(rdx, Operand(rsp, 1 * kPointerSize + extra_stack_space)); |
| 3447 // rdx is function, rax is map. | 3660 // rdx is function, rax is map. |
| 3448 | 3661 |
| 3449 // If there is a call site cache don't look in the global cache, but do the | 3662 // If there is a call site cache don't look in the global cache, but do the |
| 3450 // real lookup and update the call site cache. | 3663 // real lookup and update the call site cache. |
| 3451 if (!HasCallSiteInlineCheck()) { | 3664 if (!HasCallSiteInlineCheck()) { |
| 3452 // Look up the function and the map in the instanceof cache. | 3665 // Look up the function and the map in the instanceof cache. |
| 3453 Label miss; | 3666 Label miss; |
| 3454 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); | 3667 __ CompareRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); |
| 3455 __ j(not_equal, &miss, Label::kNear); | 3668 __ j(not_equal, &miss, Label::kNear); |
| 3456 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); | 3669 __ CompareRoot(rax, Heap::kInstanceofCacheMapRootIndex); |
| 3457 __ j(not_equal, &miss, Label::kNear); | 3670 __ j(not_equal, &miss, Label::kNear); |
| 3458 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); | 3671 __ LoadRoot(rax, Heap::kInstanceofCacheAnswerRootIndex); |
| 3459 __ ret(2 * kPointerSize); | 3672 __ ret(2 * kPointerSize); |
| 3460 __ bind(&miss); | 3673 __ bind(&miss); |
| 3461 } | 3674 } |
| 3462 | 3675 |
| 3463 __ TryGetFunctionPrototype(rdx, rbx, &slow); | 3676 __ TryGetFunctionPrototype(rdx, rbx, &slow); |
| 3464 | 3677 |
| 3465 // Check that the function prototype is a JS object. | 3678 // Check that the function prototype is a JS object. |
| 3466 __ JumpIfSmi(rbx, &slow); | 3679 __ JumpIfSmi(rbx, &slow); |
| 3467 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, kScratchRegister); | 3680 __ CmpObjectType(rbx, FIRST_SPEC_OBJECT_TYPE, kScratchRegister); |
| 3468 __ j(below, &slow); | 3681 __ j(below, &slow); |
| 3469 __ CmpInstanceType(kScratchRegister, LAST_JS_OBJECT_TYPE); | 3682 __ CmpInstanceType(kScratchRegister, LAST_SPEC_OBJECT_TYPE); |
| 3470 __ j(above, &slow); | 3683 __ j(above, &slow); |
| 3471 | 3684 |
| 3472 // Register mapping: | 3685 // Register mapping: |
| 3473 // rax is object map. | 3686 // rax is object map. |
| 3474 // rdx is function. | 3687 // rdx is function. |
| 3475 // rbx is function prototype. | 3688 // rbx is function prototype. |
| 3476 if (!HasCallSiteInlineCheck()) { | 3689 if (!HasCallSiteInlineCheck()) { |
| 3477 __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); | 3690 __ StoreRoot(rdx, Heap::kInstanceofCacheFunctionRootIndex); |
| 3478 __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex); | 3691 __ StoreRoot(rax, Heap::kInstanceofCacheMapRootIndex); |
| 3479 } else { | 3692 } else { |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3833 void StringAddStub::Generate(MacroAssembler* masm) { | 4046 void StringAddStub::Generate(MacroAssembler* masm) { |
| 3834 Label string_add_runtime, call_builtin; | 4047 Label string_add_runtime, call_builtin; |
| 3835 Builtins::JavaScript builtin_id = Builtins::ADD; | 4048 Builtins::JavaScript builtin_id = Builtins::ADD; |
| 3836 | 4049 |
| 3837 // Load the two arguments. | 4050 // Load the two arguments. |
| 3838 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left). | 4051 __ movq(rax, Operand(rsp, 2 * kPointerSize)); // First argument (left). |
| 3839 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right). | 4052 __ movq(rdx, Operand(rsp, 1 * kPointerSize)); // Second argument (right). |
| 3840 | 4053 |
| 3841 // Make sure that both arguments are strings if not known in advance. | 4054 // Make sure that both arguments are strings if not known in advance. |
| 3842 if (flags_ == NO_STRING_ADD_FLAGS) { | 4055 if (flags_ == NO_STRING_ADD_FLAGS) { |
| 3843 Condition is_smi; | 4056 __ JumpIfSmi(rax, &string_add_runtime); |
| 3844 is_smi = masm->CheckSmi(rax); | |
| 3845 __ j(is_smi, &string_add_runtime); | |
| 3846 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); | 4057 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, r8); |
| 3847 __ j(above_equal, &string_add_runtime); | 4058 __ j(above_equal, &string_add_runtime); |
| 3848 | 4059 |
| 3849 // First argument is a a string, test second. | 4060 // First argument is a a string, test second. |
| 3850 is_smi = masm->CheckSmi(rdx); | 4061 __ JumpIfSmi(rdx, &string_add_runtime); |
| 3851 __ j(is_smi, &string_add_runtime); | |
| 3852 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); | 4062 __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, r9); |
| 3853 __ j(above_equal, &string_add_runtime); | 4063 __ j(above_equal, &string_add_runtime); |
| 3854 } else { | 4064 } else { |
| 3855 // Here at least one of the arguments is definitely a string. | 4065 // Here at least one of the arguments is definitely a string. |
| 3856 // We convert the one that is not known to be a string. | 4066 // We convert the one that is not known to be a string. |
| 3857 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { | 4067 if ((flags_ & NO_STRING_CHECK_LEFT_IN_STUB) == 0) { |
| 3858 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); | 4068 ASSERT((flags_ & NO_STRING_CHECK_RIGHT_IN_STUB) != 0); |
| 3859 GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, | 4069 GenerateConvertArgument(masm, 2 * kPointerSize, rax, rbx, rcx, rdi, |
| 3860 &call_builtin); | 4070 &call_builtin); |
| 3861 builtin_id = Builtins::STRING_ADD_RIGHT; | 4071 builtin_id = Builtins::STRING_ADD_RIGHT; |
| (...skipping 1436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5298 // TODO(gc): Add call to EnsureNotWhite here. | 5508 // TODO(gc): Add call to EnsureNotWhite here. |
| 5299 // Fall through when we need to inform the incremental marker. | 5509 // Fall through when we need to inform the incremental marker. |
| 5300 } | 5510 } |
| 5301 | 5511 |
| 5302 | 5512 |
| 5303 #undef __ | 5513 #undef __ |
| 5304 | 5514 |
| 5305 } } // namespace v8::internal | 5515 } } // namespace v8::internal |
| 5306 | 5516 |
| 5307 #endif // V8_TARGET_ARCH_X64 | 5517 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |