| 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 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 } | 229 } |
| 230 | 230 |
| 231 // Return and remove the on-stack parameters. | 231 // Return and remove the on-stack parameters. |
| 232 __ ret(3 * kPointerSize); | 232 __ ret(3 * kPointerSize); |
| 233 | 233 |
| 234 __ bind(&slow_case); | 234 __ bind(&slow_case); |
| 235 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); | 235 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
| 236 } | 236 } |
| 237 | 237 |
| 238 | 238 |
| 239 // The stub returns zero for false, and a non-zero value for true. | 239 // The stub expects its argument on the stack and returns its result in tos_: |
| 240 // zero for false, and a non-zero value for true. |
| 240 void ToBooleanStub::Generate(MacroAssembler* masm) { | 241 void ToBooleanStub::Generate(MacroAssembler* masm) { |
| 241 Label false_result, true_result, not_string; | 242 Label patch; |
| 242 Factory* factory = masm->isolate()->factory(); | 243 Factory* factory = masm->isolate()->factory(); |
| 244 const Register argument = eax; |
| 243 const Register map = edx; | 245 const Register map = edx; |
| 244 | 246 |
| 245 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 247 if (!types_.IsEmpty()) { |
| 248 __ mov(argument, Operand(esp, 1 * kPointerSize)); |
| 249 } |
| 246 | 250 |
| 247 // undefined -> false | 251 // undefined -> false |
| 248 __ cmp(eax, factory->undefined_value()); | 252 CheckOddball(masm, UNDEFINED, Heap::kUndefinedValueRootIndex, false, &patch); |
| 249 __ j(equal, &false_result); | |
| 250 | 253 |
| 251 // Boolean -> its value | 254 // Boolean -> its value |
| 252 __ cmp(eax, factory->false_value()); | 255 CheckOddball(masm, BOOLEAN, Heap::kFalseValueRootIndex, false, &patch); |
| 253 __ j(equal, &false_result); | 256 CheckOddball(masm, BOOLEAN, Heap::kTrueValueRootIndex, true, &patch); |
| 254 __ cmp(eax, factory->true_value()); | |
| 255 __ j(equal, &true_result); | |
| 256 | |
| 257 // Smis: 0 -> false, all other -> true | |
| 258 __ test(eax, Operand(eax)); | |
| 259 __ j(zero, &false_result); | |
| 260 __ JumpIfSmi(eax, &true_result); | |
| 261 | 257 |
| 262 // 'null' -> false. | 258 // 'null' -> false. |
| 263 __ cmp(eax, factory->null_value()); | 259 CheckOddball(masm, NULL_TYPE, Heap::kNullValueRootIndex, false, &patch); |
| 264 __ j(equal, &false_result, Label::kNear); | |
| 265 | 260 |
| 266 // Get the map of the heap object. | 261 if (types_.Contains(SMI)) { |
| 267 __ mov(map, FieldOperand(eax, HeapObject::kMapOffset)); | 262 // Smis: 0 -> false, all other -> true |
| 263 Label not_smi; |
| 264 __ JumpIfNotSmi(argument, ¬_smi, Label::kNear); |
| 265 // argument contains the correct return value already |
| 266 if (!tos_.is(argument)) { |
| 267 __ mov(tos_, argument); |
| 268 } |
| 269 __ ret(1 * kPointerSize); |
| 270 __ bind(¬_smi); |
| 271 } else if (types_.NeedsMap()) { |
| 272 // If we need a map later and have a Smi -> patch. |
| 273 __ JumpIfSmi(argument, &patch, Label::kNear); |
| 274 } |
| 268 | 275 |
| 269 // Undetectable -> false. | 276 if (types_.NeedsMap()) { |
| 270 __ test_b(FieldOperand(map, Map::kBitFieldOffset), | 277 __ mov(map, FieldOperand(argument, HeapObject::kMapOffset)); |
| 271 1 << Map::kIsUndetectable); | |
| 272 __ j(not_zero, &false_result, Label::kNear); | |
| 273 | 278 |
| 274 // JavaScript object -> true. | 279 // Everything with a map could be undetectable, so check this now. |
| 275 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); | 280 __ test_b(FieldOperand(map, Map::kBitFieldOffset), |
| 276 __ j(above_equal, &true_result, Label::kNear); | 281 1 << Map::kIsUndetectable); |
| 282 // Undetectable -> false. |
| 283 Label not_undetectable; |
| 284 __ j(zero, ¬_undetectable, Label::kNear); |
| 285 __ Set(tos_, Immediate(0)); |
| 286 __ ret(1 * kPointerSize); |
| 287 __ bind(¬_undetectable); |
| 288 } |
| 277 | 289 |
| 278 // String value -> false iff empty. | 290 if (types_.Contains(SPEC_OBJECT)) { |
| 279 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); | 291 // spec object -> true. |
| 280 __ j(above_equal, ¬_string, Label::kNear); | 292 Label not_js_object; |
| 281 __ cmp(FieldOperand(eax, String::kLengthOffset), Immediate(0)); | 293 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
| 282 __ j(zero, &false_result, Label::kNear); | 294 __ j(below, ¬_js_object, Label::kNear); |
| 283 __ jmp(&true_result, Label::kNear); | 295 __ Set(tos_, Immediate(1)); |
| 296 __ ret(1 * kPointerSize); |
| 297 __ bind(¬_js_object); |
| 298 } else if (types_.Contains(INTERNAL_OBJECT)) { |
| 299 // We've seen a spec object for the first time -> patch. |
| 300 __ CmpInstanceType(map, FIRST_SPEC_OBJECT_TYPE); |
| 301 __ j(above_equal, &patch, Label::kNear); |
| 302 } |
| 284 | 303 |
| 285 __ bind(¬_string); | 304 if (types_.Contains(STRING)) { |
| 286 // HeapNumber -> false iff +0, -0, or NaN. | 305 // String value -> false iff empty. |
| 287 __ cmp(map, factory->heap_number_map()); | 306 Label not_string; |
| 288 __ j(not_equal, &true_result, Label::kNear); | 307 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); |
| 289 __ fldz(); | 308 __ j(above_equal, ¬_string, Label::kNear); |
| 290 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 309 __ mov(tos_, FieldOperand(argument, String::kLengthOffset)); |
| 291 __ FCmp(); | 310 __ ret(1 * kPointerSize); // the string length is OK as the return value |
| 292 __ j(zero, &false_result, Label::kNear); | 311 __ bind(¬_string); |
| 293 // Fall through to |true_result|. | 312 } else if (types_.Contains(INTERNAL_OBJECT)) { |
| 313 // We've seen a string for the first time -> patch |
| 314 __ CmpInstanceType(map, FIRST_NONSTRING_TYPE); |
| 315 __ j(below, &patch, Label::kNear); |
| 316 } |
| 294 | 317 |
| 295 // Return 1/0 for true/false in tos_. | 318 if (types_.Contains(HEAP_NUMBER)) { |
| 296 __ bind(&true_result); | 319 // heap number -> false iff +0, -0, or NaN. |
| 297 __ mov(tos_, 1); | 320 Label not_heap_number, false_result; |
| 298 __ ret(1 * kPointerSize); | 321 __ cmp(map, factory->heap_number_map()); |
| 299 __ bind(&false_result); | 322 __ j(not_equal, ¬_heap_number, Label::kNear); |
| 300 __ mov(tos_, 0); | 323 __ fldz(); |
| 301 __ ret(1 * kPointerSize); | 324 __ fld_d(FieldOperand(argument, HeapNumber::kValueOffset)); |
| 325 __ FCmp(); |
| 326 __ j(zero, &false_result, Label::kNear); |
| 327 __ Set(tos_, Immediate(1)); |
| 328 __ ret(1 * kPointerSize); |
| 329 __ bind(&false_result); |
| 330 __ Set(tos_, Immediate(0)); |
| 331 __ ret(1 * kPointerSize); |
| 332 __ bind(¬_heap_number); |
| 333 } else if (types_.Contains(INTERNAL_OBJECT)) { |
| 334 // We've seen a heap number for the first time -> patch |
| 335 __ cmp(map, factory->heap_number_map()); |
| 336 __ j(equal, &patch, Label::kNear); |
| 337 } |
| 338 |
| 339 if (types_.Contains(INTERNAL_OBJECT)) { |
| 340 // internal objects -> true |
| 341 __ Set(tos_, Immediate(1)); |
| 342 __ ret(1 * kPointerSize); |
| 343 } |
| 344 |
| 345 if (!types_.IsAll()) { |
| 346 __ bind(&patch); |
| 347 GenerateTypeTransition(masm); |
| 348 } |
| 302 } | 349 } |
| 303 | 350 |
| 304 | 351 |
| 305 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { | 352 void StoreBufferOverflowStub::Generate(MacroAssembler* masm) { |
| 306 // We don't allow a GC during a store buffer overflow so there is no need to | 353 // We don't allow a GC during a store buffer overflow so there is no need to |
| 307 // store the registers in any particular way, but we do have to store and | 354 // store the registers in any particular way, but we do have to store and |
| 308 // restore them. | 355 // restore them. |
| 309 __ pushad(); | 356 __ pushad(); |
| 310 if (save_doubles_ == kSaveFPRegs) { | 357 if (save_doubles_ == kSaveFPRegs) { |
| 311 CpuFeatures::Scope scope(SSE2); | 358 CpuFeatures::Scope scope(SSE2); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 328 XMMRegister reg = XMMRegister::from_code(i); | 375 XMMRegister reg = XMMRegister::from_code(i); |
| 329 __ movdbl(reg, Operand(esp, i * kDoubleSize)); | 376 __ movdbl(reg, Operand(esp, i * kDoubleSize)); |
| 330 } | 377 } |
| 331 __ add(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters)); | 378 __ add(Operand(esp), Immediate(kDoubleSize * XMMRegister::kNumRegisters)); |
| 332 } | 379 } |
| 333 __ popad(); | 380 __ popad(); |
| 334 __ ret(0); | 381 __ ret(0); |
| 335 } | 382 } |
| 336 | 383 |
| 337 | 384 |
| 385 void ToBooleanStub::CheckOddball(MacroAssembler* masm, |
| 386 Type type, |
| 387 Heap::RootListIndex value, |
| 388 bool result, |
| 389 Label* patch) { |
| 390 const Register argument = eax; |
| 391 if (types_.Contains(type)) { |
| 392 // If we see an expected oddball, return its ToBoolean value tos_. |
| 393 Label different_value; |
| 394 __ CompareRoot(argument, value); |
| 395 __ j(not_equal, &different_value, Label::kNear); |
| 396 __ Set(tos_, Immediate(result ? 1 : 0)); |
| 397 __ ret(1 * kPointerSize); |
| 398 __ bind(&different_value); |
| 399 } else if (types_.Contains(INTERNAL_OBJECT)) { |
| 400 // If we see an unexpected oddball and handle internal objects, we must |
| 401 // patch because the code for internal objects doesn't handle it explictly. |
| 402 __ CompareRoot(argument, value); |
| 403 __ j(equal, patch); |
| 404 } |
| 405 } |
| 406 |
| 407 |
| 408 void ToBooleanStub::GenerateTypeTransition(MacroAssembler* masm) { |
| 409 __ pop(ecx); // Get return address, operand is now on top of stack. |
| 410 __ push(Immediate(Smi::FromInt(tos_.code()))); |
| 411 __ push(Immediate(Smi::FromInt(types_.ToByte()))); |
| 412 __ push(ecx); // Push return address. |
| 413 // Patch the caller to an appropriate specialized stub and return the |
| 414 // operation result to the caller of the stub. |
| 415 __ TailCallExternalReference( |
| 416 ExternalReference(IC_Utility(IC::kToBoolean_Patch), masm->isolate()), |
| 417 3, |
| 418 1); |
| 419 } |
| 420 |
| 421 |
| 338 class FloatingPointHelper : public AllStatic { | 422 class FloatingPointHelper : public AllStatic { |
| 339 public: | 423 public: |
| 340 enum ArgLocation { | 424 enum ArgLocation { |
| 341 ARGS_ON_STACK, | 425 ARGS_ON_STACK, |
| 342 ARGS_IN_REGISTERS | 426 ARGS_IN_REGISTERS |
| 343 }; | 427 }; |
| 344 | 428 |
| 345 // Code pattern for loading a floating point value. Input value must | 429 // Code pattern for loading a floating point value. Input value must |
| 346 // be either a smi or a heap number object (fp value). Requirements: | 430 // be either a smi or a heap number object (fp value). Requirements: |
| 347 // operand in register number. Returns operand as floating point number | 431 // operand in register number. Returns operand as floating point number |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 537 __ j(greater, &negative, Label::kNear); | 621 __ j(greater, &negative, Label::kNear); |
| 538 __ mov(ecx, scratch2); | 622 __ mov(ecx, scratch2); |
| 539 __ jmp(&done, Label::kNear); | 623 __ jmp(&done, Label::kNear); |
| 540 __ bind(&negative); | 624 __ bind(&negative); |
| 541 __ sub(ecx, Operand(scratch2)); | 625 __ sub(ecx, Operand(scratch2)); |
| 542 __ bind(&done); | 626 __ bind(&done); |
| 543 } | 627 } |
| 544 } | 628 } |
| 545 | 629 |
| 546 | 630 |
| 547 const char* UnaryOpStub::GetName() { | 631 void UnaryOpStub::PrintName(StringStream* stream) { |
| 548 if (name_ != NULL) return name_; | |
| 549 const int kMaxNameLength = 100; | |
| 550 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( | |
| 551 kMaxNameLength); | |
| 552 if (name_ == NULL) return "OOM"; | |
| 553 const char* op_name = Token::Name(op_); | 632 const char* op_name = Token::Name(op_); |
| 554 const char* overwrite_name = NULL; // Make g++ happy. | 633 const char* overwrite_name = NULL; // Make g++ happy. |
| 555 switch (mode_) { | 634 switch (mode_) { |
| 556 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; | 635 case UNARY_NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 557 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; | 636 case UNARY_OVERWRITE: overwrite_name = "Overwrite"; break; |
| 558 } | 637 } |
| 559 | 638 stream->Add("UnaryOpStub_%s_%s_%s", |
| 560 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 639 op_name, |
| 561 "UnaryOpStub_%s_%s_%s", | 640 overwrite_name, |
| 562 op_name, | 641 UnaryOpIC::GetName(operand_type_)); |
| 563 overwrite_name, | |
| 564 UnaryOpIC::GetName(operand_type_)); | |
| 565 return name_; | |
| 566 } | 642 } |
| 567 | 643 |
| 568 | 644 |
| 569 // TODO(svenpanne): Use virtual functions instead of switch. | 645 // TODO(svenpanne): Use virtual functions instead of switch. |
| 570 void UnaryOpStub::Generate(MacroAssembler* masm) { | 646 void UnaryOpStub::Generate(MacroAssembler* masm) { |
| 571 switch (operand_type_) { | 647 switch (operand_type_) { |
| 572 case UnaryOpIC::UNINITIALIZED: | 648 case UnaryOpIC::UNINITIALIZED: |
| 573 GenerateTypeTransition(masm); | 649 GenerateTypeTransition(masm); |
| 574 break; | 650 break; |
| 575 case UnaryOpIC::SMI: | 651 case UnaryOpIC::SMI: |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 940 break; | 1016 break; |
| 941 case BinaryOpIC::GENERIC: | 1017 case BinaryOpIC::GENERIC: |
| 942 GenerateGeneric(masm); | 1018 GenerateGeneric(masm); |
| 943 break; | 1019 break; |
| 944 default: | 1020 default: |
| 945 UNREACHABLE(); | 1021 UNREACHABLE(); |
| 946 } | 1022 } |
| 947 } | 1023 } |
| 948 | 1024 |
| 949 | 1025 |
| 950 const char* BinaryOpStub::GetName() { | 1026 void BinaryOpStub::PrintName(StringStream* stream) { |
| 951 if (name_ != NULL) return name_; | |
| 952 const int kMaxNameLength = 100; | |
| 953 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( | |
| 954 kMaxNameLength); | |
| 955 if (name_ == NULL) return "OOM"; | |
| 956 const char* op_name = Token::Name(op_); | 1027 const char* op_name = Token::Name(op_); |
| 957 const char* overwrite_name; | 1028 const char* overwrite_name; |
| 958 switch (mode_) { | 1029 switch (mode_) { |
| 959 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 1030 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 960 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 1031 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
| 961 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 1032 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
| 962 default: overwrite_name = "UnknownOverwrite"; break; | 1033 default: overwrite_name = "UnknownOverwrite"; break; |
| 963 } | 1034 } |
| 964 | 1035 stream->Add("BinaryOpStub_%s_%s_%s", |
| 965 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 1036 op_name, |
| 966 "BinaryOpStub_%s_%s_%s", | 1037 overwrite_name, |
| 967 op_name, | 1038 BinaryOpIC::GetName(operands_type_)); |
| 968 overwrite_name, | |
| 969 BinaryOpIC::GetName(operands_type_)); | |
| 970 return name_; | |
| 971 } | 1039 } |
| 972 | 1040 |
| 973 | 1041 |
| 974 void BinaryOpStub::GenerateSmiCode( | 1042 void BinaryOpStub::GenerateSmiCode( |
| 975 MacroAssembler* masm, | 1043 MacroAssembler* masm, |
| 976 Label* slow, | 1044 Label* slow, |
| 977 SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { | 1045 SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { |
| 978 // 1. Move arguments into edx, eax except for DIV and MOD, which need the | 1046 // 1. Move arguments into edx, eax except for DIV and MOD, which need the |
| 979 // dividend in eax and edx free for the division. Use eax, ebx for those. | 1047 // dividend in eax and edx free for the division. Use eax, ebx for those. |
| 980 Comment load_comment(masm, "-- Load arguments"); | 1048 Comment load_comment(masm, "-- Load arguments"); |
| (...skipping 3225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4206 // Slow-case: Non-function called. | 4274 // Slow-case: Non-function called. |
| 4207 __ bind(&slow); | 4275 __ bind(&slow); |
| 4208 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead | 4276 // CALL_NON_FUNCTION expects the non-function callee as receiver (instead |
| 4209 // of the original receiver from the call site). | 4277 // of the original receiver from the call site). |
| 4210 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi); | 4278 __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edi); |
| 4211 __ Set(eax, Immediate(argc_)); | 4279 __ Set(eax, Immediate(argc_)); |
| 4212 __ Set(ebx, Immediate(0)); | 4280 __ Set(ebx, Immediate(0)); |
| 4213 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); | 4281 __ GetBuiltinEntry(edx, Builtins::CALL_NON_FUNCTION); |
| 4214 Handle<Code> adaptor = | 4282 Handle<Code> adaptor = |
| 4215 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); | 4283 masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); |
| 4284 __ SetCallKind(ecx, CALL_AS_METHOD); |
| 4216 __ jmp(adaptor, RelocInfo::CODE_TARGET); | 4285 __ jmp(adaptor, RelocInfo::CODE_TARGET); |
| 4217 } | 4286 } |
| 4218 | 4287 |
| 4219 | 4288 |
| 4220 bool CEntryStub::NeedsImmovableCode() { | 4289 bool CEntryStub::NeedsImmovableCode() { |
| 4221 return false; | 4290 return false; |
| 4222 } | 4291 } |
| 4223 | 4292 |
| 4224 | 4293 |
| 4225 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { | 4294 void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) { |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4412 __ bind(&throw_termination_exception); | 4481 __ bind(&throw_termination_exception); |
| 4413 GenerateThrowUncatchable(masm, TERMINATION); | 4482 GenerateThrowUncatchable(masm, TERMINATION); |
| 4414 | 4483 |
| 4415 __ bind(&throw_normal_exception); | 4484 __ bind(&throw_normal_exception); |
| 4416 GenerateThrowTOS(masm); | 4485 GenerateThrowTOS(masm); |
| 4417 } | 4486 } |
| 4418 | 4487 |
| 4419 | 4488 |
| 4420 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { | 4489 void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { |
| 4421 Label invoke, exit; | 4490 Label invoke, exit; |
| 4422 #ifdef ENABLE_LOGGING_AND_PROFILING | |
| 4423 Label not_outermost_js, not_outermost_js_2; | 4491 Label not_outermost_js, not_outermost_js_2; |
| 4424 #endif | |
| 4425 | 4492 |
| 4426 // Setup frame. | 4493 // Setup frame. |
| 4427 __ push(ebp); | 4494 __ push(ebp); |
| 4428 __ mov(ebp, Operand(esp)); | 4495 __ mov(ebp, Operand(esp)); |
| 4429 | 4496 |
| 4430 // Push marker in two places. | 4497 // Push marker in two places. |
| 4431 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; | 4498 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; |
| 4432 __ push(Immediate(Smi::FromInt(marker))); // context slot | 4499 __ push(Immediate(Smi::FromInt(marker))); // context slot |
| 4433 __ push(Immediate(Smi::FromInt(marker))); // function slot | 4500 __ push(Immediate(Smi::FromInt(marker))); // function slot |
| 4434 // Save callee-saved registers (C calling conventions). | 4501 // Save callee-saved registers (C calling conventions). |
| 4435 __ push(edi); | 4502 __ push(edi); |
| 4436 __ push(esi); | 4503 __ push(esi); |
| 4437 __ push(ebx); | 4504 __ push(ebx); |
| 4438 | 4505 |
| 4439 // Save copies of the top frame descriptor on the stack. | 4506 // Save copies of the top frame descriptor on the stack. |
| 4440 ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, masm->isolate()); | 4507 ExternalReference c_entry_fp(Isolate::k_c_entry_fp_address, masm->isolate()); |
| 4441 __ push(Operand::StaticVariable(c_entry_fp)); | 4508 __ push(Operand::StaticVariable(c_entry_fp)); |
| 4442 | 4509 |
| 4443 #ifdef ENABLE_LOGGING_AND_PROFILING | |
| 4444 // If this is the outermost JS call, set js_entry_sp value. | 4510 // If this is the outermost JS call, set js_entry_sp value. |
| 4445 ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, | 4511 ExternalReference js_entry_sp(Isolate::k_js_entry_sp_address, |
| 4446 masm->isolate()); | 4512 masm->isolate()); |
| 4447 __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0)); | 4513 __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0)); |
| 4448 __ j(not_equal, ¬_outermost_js); | 4514 __ j(not_equal, ¬_outermost_js); |
| 4449 __ mov(Operand::StaticVariable(js_entry_sp), ebp); | 4515 __ mov(Operand::StaticVariable(js_entry_sp), ebp); |
| 4450 __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); | 4516 __ push(Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); |
| 4451 Label cont; | 4517 Label cont; |
| 4452 __ jmp(&cont); | 4518 __ jmp(&cont); |
| 4453 __ bind(¬_outermost_js); | 4519 __ bind(¬_outermost_js); |
| 4454 __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME))); | 4520 __ push(Immediate(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME))); |
| 4455 __ bind(&cont); | 4521 __ bind(&cont); |
| 4456 #endif | |
| 4457 | 4522 |
| 4458 // Call a faked try-block that does the invoke. | 4523 // Call a faked try-block that does the invoke. |
| 4459 __ call(&invoke); | 4524 __ call(&invoke); |
| 4460 | 4525 |
| 4461 // Caught exception: Store result (exception) in the pending | 4526 // Caught exception: Store result (exception) in the pending |
| 4462 // exception field in the JSEnv and return a failure sentinel. | 4527 // exception field in the JSEnv and return a failure sentinel. |
| 4463 ExternalReference pending_exception(Isolate::k_pending_exception_address, | 4528 ExternalReference pending_exception(Isolate::k_pending_exception_address, |
| 4464 masm->isolate()); | 4529 masm->isolate()); |
| 4465 __ mov(Operand::StaticVariable(pending_exception), eax); | 4530 __ mov(Operand::StaticVariable(pending_exception), eax); |
| 4466 __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception())); | 4531 __ mov(eax, reinterpret_cast<int32_t>(Failure::Exception())); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 4494 __ mov(edx, Immediate(entry)); | 4559 __ mov(edx, Immediate(entry)); |
| 4495 } | 4560 } |
| 4496 __ mov(edx, Operand(edx, 0)); // deref address | 4561 __ mov(edx, Operand(edx, 0)); // deref address |
| 4497 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); | 4562 __ lea(edx, FieldOperand(edx, Code::kHeaderSize)); |
| 4498 __ call(Operand(edx)); | 4563 __ call(Operand(edx)); |
| 4499 | 4564 |
| 4500 // Unlink this frame from the handler chain. | 4565 // Unlink this frame from the handler chain. |
| 4501 __ PopTryHandler(); | 4566 __ PopTryHandler(); |
| 4502 | 4567 |
| 4503 __ bind(&exit); | 4568 __ bind(&exit); |
| 4504 #ifdef ENABLE_LOGGING_AND_PROFILING | |
| 4505 // Check if the current stack frame is marked as the outermost JS frame. | 4569 // Check if the current stack frame is marked as the outermost JS frame. |
| 4506 __ pop(ebx); | 4570 __ pop(ebx); |
| 4507 __ cmp(Operand(ebx), | 4571 __ cmp(Operand(ebx), |
| 4508 Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); | 4572 Immediate(Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME))); |
| 4509 __ j(not_equal, ¬_outermost_js_2); | 4573 __ j(not_equal, ¬_outermost_js_2); |
| 4510 __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); | 4574 __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); |
| 4511 __ bind(¬_outermost_js_2); | 4575 __ bind(¬_outermost_js_2); |
| 4512 #endif | |
| 4513 | 4576 |
| 4514 // Restore the top frame descriptor from the stack. | 4577 // Restore the top frame descriptor from the stack. |
| 4515 __ pop(Operand::StaticVariable(ExternalReference( | 4578 __ pop(Operand::StaticVariable(ExternalReference( |
| 4516 Isolate::k_c_entry_fp_address, | 4579 Isolate::k_c_entry_fp_address, |
| 4517 masm->isolate()))); | 4580 masm->isolate()))); |
| 4518 | 4581 |
| 4519 // Restore callee-saved registers (C calling conventions). | 4582 // Restore callee-saved registers (C calling conventions). |
| 4520 __ pop(ebx); | 4583 __ pop(ebx); |
| 4521 __ pop(esi); | 4584 __ pop(esi); |
| 4522 __ pop(edi); | 4585 __ pop(edi); |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4764 | RegisterField::encode(false) // lhs_ and rhs_ are not used | 4827 | RegisterField::encode(false) // lhs_ and rhs_ are not used |
| 4765 | StrictField::encode(strict_) | 4828 | StrictField::encode(strict_) |
| 4766 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) | 4829 | NeverNanNanField::encode(cc_ == equal ? never_nan_nan_ : false) |
| 4767 | IncludeNumberCompareField::encode(include_number_compare_) | 4830 | IncludeNumberCompareField::encode(include_number_compare_) |
| 4768 | IncludeSmiCompareField::encode(include_smi_compare_); | 4831 | IncludeSmiCompareField::encode(include_smi_compare_); |
| 4769 } | 4832 } |
| 4770 | 4833 |
| 4771 | 4834 |
| 4772 // Unfortunately you have to run without snapshots to see most of these | 4835 // Unfortunately you have to run without snapshots to see most of these |
| 4773 // names in the profile since most compare stubs end up in the snapshot. | 4836 // names in the profile since most compare stubs end up in the snapshot. |
| 4774 const char* CompareStub::GetName() { | 4837 void CompareStub::PrintName(StringStream* stream) { |
| 4775 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); | 4838 ASSERT(lhs_.is(no_reg) && rhs_.is(no_reg)); |
| 4776 | |
| 4777 if (name_ != NULL) return name_; | |
| 4778 const int kMaxNameLength = 100; | |
| 4779 name_ = Isolate::Current()->bootstrapper()->AllocateAutoDeletedArray( | |
| 4780 kMaxNameLength); | |
| 4781 if (name_ == NULL) return "OOM"; | |
| 4782 | |
| 4783 const char* cc_name; | 4839 const char* cc_name; |
| 4784 switch (cc_) { | 4840 switch (cc_) { |
| 4785 case less: cc_name = "LT"; break; | 4841 case less: cc_name = "LT"; break; |
| 4786 case greater: cc_name = "GT"; break; | 4842 case greater: cc_name = "GT"; break; |
| 4787 case less_equal: cc_name = "LE"; break; | 4843 case less_equal: cc_name = "LE"; break; |
| 4788 case greater_equal: cc_name = "GE"; break; | 4844 case greater_equal: cc_name = "GE"; break; |
| 4789 case equal: cc_name = "EQ"; break; | 4845 case equal: cc_name = "EQ"; break; |
| 4790 case not_equal: cc_name = "NE"; break; | 4846 case not_equal: cc_name = "NE"; break; |
| 4791 default: cc_name = "UnknownCondition"; break; | 4847 default: cc_name = "UnknownCondition"; break; |
| 4792 } | 4848 } |
| 4793 | 4849 bool is_equality = cc_ == equal || cc_ == not_equal; |
| 4794 const char* strict_name = ""; | 4850 stream->Add("CompareStub_%s", cc_name); |
| 4795 if (strict_ && (cc_ == equal || cc_ == not_equal)) { | 4851 if (strict_ && is_equality) stream->Add("_STRICT"); |
| 4796 strict_name = "_STRICT"; | 4852 if (never_nan_nan_ && is_equality) stream->Add("_NO_NAN"); |
| 4797 } | 4853 if (!include_number_compare_) stream->Add("_NO_NUMBER"); |
| 4798 | 4854 if (!include_smi_compare_) stream->Add("_NO_SMI"); |
| 4799 const char* never_nan_nan_name = ""; | |
| 4800 if (never_nan_nan_ && (cc_ == equal || cc_ == not_equal)) { | |
| 4801 never_nan_nan_name = "_NO_NAN"; | |
| 4802 } | |
| 4803 | |
| 4804 const char* include_number_compare_name = ""; | |
| 4805 if (!include_number_compare_) { | |
| 4806 include_number_compare_name = "_NO_NUMBER"; | |
| 4807 } | |
| 4808 | |
| 4809 const char* include_smi_compare_name = ""; | |
| 4810 if (!include_smi_compare_) { | |
| 4811 include_smi_compare_name = "_NO_SMI"; | |
| 4812 } | |
| 4813 | |
| 4814 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | |
| 4815 "CompareStub_%s%s%s%s%s", | |
| 4816 cc_name, | |
| 4817 strict_name, | |
| 4818 never_nan_nan_name, | |
| 4819 include_number_compare_name, | |
| 4820 include_smi_compare_name); | |
| 4821 return name_; | |
| 4822 } | 4855 } |
| 4823 | 4856 |
| 4824 | 4857 |
| 4825 // ------------------------------------------------------------------------- | 4858 // ------------------------------------------------------------------------- |
| 4826 // StringCharCodeAtGenerator | 4859 // StringCharCodeAtGenerator |
| 4827 | 4860 |
| 4828 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { | 4861 void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) { |
| 4829 Label flat_string; | 4862 Label flat_string; |
| 4830 Label ascii_string; | 4863 Label ascii_string; |
| 4831 Label got_char_code; | 4864 Label got_char_code; |
| (...skipping 1736 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6568 | 6601 |
| 6569 // Fall through when we need to inform the incremental marker. | 6602 // Fall through when we need to inform the incremental marker. |
| 6570 } | 6603 } |
| 6571 | 6604 |
| 6572 | 6605 |
| 6573 #undef __ | 6606 #undef __ |
| 6574 | 6607 |
| 6575 } } // namespace v8::internal | 6608 } } // namespace v8::internal |
| 6576 | 6609 |
| 6577 #endif // V8_TARGET_ARCH_IA32 | 6610 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |