| 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 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 __ lea(rdx, | 193 __ lea(rdx, |
| 194 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset)); | 194 Operand(rbp, StandardFrameConstants::kCallerSPOffset + offset)); |
| 195 __ push(rdx); | 195 __ push(rdx); |
| 196 __ Push(Smi::FromInt(scope()->num_parameters())); | 196 __ Push(Smi::FromInt(scope()->num_parameters())); |
| 197 // Arguments to ArgumentsAccessStub: | 197 // Arguments to ArgumentsAccessStub: |
| 198 // function, receiver address, parameter count. | 198 // function, receiver address, parameter count. |
| 199 // The stub will rewrite receiver and parameter count if the previous | 199 // The stub will rewrite receiver and parameter count if the previous |
| 200 // stack frame was an arguments adapter frame. | 200 // stack frame was an arguments adapter frame. |
| 201 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 201 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 202 __ CallStub(&stub); | 202 __ CallStub(&stub); |
| 203 // Store new arguments object in both "arguments" and ".arguments" slots. | 203 |
| 204 __ movq(rcx, rax); | 204 Variable* arguments_shadow = scope()->arguments_shadow(); |
| 205 if (arguments_shadow != NULL) { |
| 206 // Store new arguments object in both "arguments" and ".arguments" slots. |
| 207 __ movq(rcx, rax); |
| 208 Move(arguments_shadow->AsSlot(), rcx, rbx, rdx); |
| 209 } |
| 205 Move(arguments->AsSlot(), rax, rbx, rdx); | 210 Move(arguments->AsSlot(), rax, rbx, rdx); |
| 206 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot(); | |
| 207 Move(dot_arguments_slot, rcx, rbx, rdx); | |
| 208 } | |
| 209 | |
| 210 { Comment cmnt(masm_, "[ Declarations"); | |
| 211 // For named function expressions, declare the function name as a | |
| 212 // constant. | |
| 213 if (scope()->is_function_scope() && scope()->function() != NULL) { | |
| 214 EmitDeclaration(scope()->function(), Variable::CONST, NULL); | |
| 215 } | |
| 216 // Visit all the explicit declarations unless there is an illegal | |
| 217 // redeclaration. | |
| 218 if (scope()->HasIllegalRedeclaration()) { | |
| 219 scope()->VisitIllegalRedeclaration(this); | |
| 220 } else { | |
| 221 VisitDeclarations(scope()->declarations()); | |
| 222 } | |
| 223 } | 211 } |
| 224 | 212 |
| 225 if (FLAG_trace) { | 213 if (FLAG_trace) { |
| 226 __ CallRuntime(Runtime::kTraceEnter, 0); | 214 __ CallRuntime(Runtime::kTraceEnter, 0); |
| 227 } | 215 } |
| 228 | 216 |
| 229 { Comment cmnt(masm_, "[ Stack check"); | 217 // Visit the declarations and body unless there is an illegal |
| 230 PrepareForBailout(info->function(), NO_REGISTERS); | 218 // redeclaration. |
| 231 NearLabel ok; | 219 if (scope()->HasIllegalRedeclaration()) { |
| 232 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 220 Comment cmnt(masm_, "[ Declarations"); |
| 233 __ j(above_equal, &ok); | 221 scope()->VisitIllegalRedeclaration(this); |
| 234 StackCheckStub stub; | 222 } else { |
| 235 __ CallStub(&stub); | 223 { Comment cmnt(masm_, "[ Declarations"); |
| 236 __ bind(&ok); | 224 // For named function expressions, declare the function name as a |
| 225 // constant. |
| 226 if (scope()->is_function_scope() && scope()->function() != NULL) { |
| 227 EmitDeclaration(scope()->function(), Variable::CONST, NULL); |
| 228 } |
| 229 VisitDeclarations(scope()->declarations()); |
| 230 } |
| 231 |
| 232 { Comment cmnt(masm_, "[ Stack check"); |
| 233 PrepareForBailout(info->function(), NO_REGISTERS); |
| 234 NearLabel ok; |
| 235 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
| 236 __ j(above_equal, &ok); |
| 237 StackCheckStub stub; |
| 238 __ CallStub(&stub); |
| 239 __ bind(&ok); |
| 240 } |
| 241 |
| 242 { Comment cmnt(masm_, "[ Body"); |
| 243 ASSERT(loop_depth() == 0); |
| 244 VisitStatements(function()->body()); |
| 245 ASSERT(loop_depth() == 0); |
| 246 } |
| 237 } | 247 } |
| 238 | 248 |
| 239 { Comment cmnt(masm_, "[ Body"); | 249 // Always emit a 'return undefined' in case control fell off the end of |
| 240 ASSERT(loop_depth() == 0); | 250 // the body. |
| 241 VisitStatements(function()->body()); | |
| 242 ASSERT(loop_depth() == 0); | |
| 243 } | |
| 244 | |
| 245 { Comment cmnt(masm_, "[ return <undefined>;"); | 251 { Comment cmnt(masm_, "[ return <undefined>;"); |
| 246 // Emit a 'return undefined' in case control fell off the end of the body. | |
| 247 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | 252 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 248 EmitReturnSequence(); | 253 EmitReturnSequence(); |
| 249 } | 254 } |
| 250 } | 255 } |
| 251 | 256 |
| 252 | 257 |
| 253 void FullCodeGenerator::ClearAccumulator() { | 258 void FullCodeGenerator::ClearAccumulator() { |
| 254 __ Set(rax, 0); | 259 __ Set(rax, 0); |
| 255 } | 260 } |
| 256 | 261 |
| 257 | 262 |
| 258 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) { | 263 void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) { |
| 259 Comment cmnt(masm_, "[ Stack check"); | 264 Comment cmnt(masm_, "[ Stack check"); |
| 260 NearLabel ok; | 265 NearLabel ok; |
| 261 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 266 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
| 262 __ j(above_equal, &ok); | 267 __ j(above_equal, &ok); |
| 263 StackCheckStub stub; | 268 StackCheckStub stub; |
| 264 __ CallStub(&stub); | 269 __ CallStub(&stub); |
| 265 // Record a mapping of this PC offset to the OSR id. This is used to find | 270 // Record a mapping of this PC offset to the OSR id. This is used to find |
| 266 // the AST id from the unoptimized code in order to use it as a key into | 271 // the AST id from the unoptimized code in order to use it as a key into |
| 267 // the deoptimization input data found in the optimized code. | 272 // the deoptimization input data found in the optimized code. |
| 268 RecordStackCheck(stmt->OsrEntryId()); | 273 RecordStackCheck(stmt->OsrEntryId()); |
| 269 | 274 |
| 275 // Loop stack checks can be patched to perform on-stack replacement. In |
| 276 // order to decide whether or not to perform OSR we embed the loop depth |
| 277 // in a test instruction after the call so we can extract it from the OSR |
| 278 // builtin. |
| 279 ASSERT(loop_depth() > 0); |
| 280 __ testl(rax, Immediate(Min(loop_depth(), Code::kMaxLoopNestingMarker))); |
| 281 |
| 270 __ bind(&ok); | 282 __ bind(&ok); |
| 271 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); | 283 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
| 272 // Record a mapping of the OSR id to this PC. This is used if the OSR | 284 // Record a mapping of the OSR id to this PC. This is used if the OSR |
| 273 // entry becomes the target of a bailout. We don't expect it to be, but | 285 // entry becomes the target of a bailout. We don't expect it to be, but |
| 274 // we want it to work if it is. | 286 // we want it to work if it is. |
| 275 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS); | 287 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS); |
| 276 } | 288 } |
| 277 | 289 |
| 278 | 290 |
| 279 void FullCodeGenerator::EmitReturnSequence() { | 291 void FullCodeGenerator::EmitReturnSequence() { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 } | 323 } |
| 312 // Check that the size of the code used for returning is large enough | 324 // Check that the size of the code used for returning is large enough |
| 313 // for the debugger's requirements. | 325 // for the debugger's requirements. |
| 314 ASSERT(Assembler::kJSReturnSequenceLength <= | 326 ASSERT(Assembler::kJSReturnSequenceLength <= |
| 315 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 327 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 316 #endif | 328 #endif |
| 317 } | 329 } |
| 318 } | 330 } |
| 319 | 331 |
| 320 | 332 |
| 321 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand( | |
| 322 Token::Value op, Expression* left, Expression* right) { | |
| 323 ASSERT(ShouldInlineSmiCase(op)); | |
| 324 return kNoConstants; | |
| 325 } | |
| 326 | |
| 327 | |
| 328 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { | 333 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { |
| 329 } | 334 } |
| 330 | 335 |
| 331 | 336 |
| 332 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { | 337 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { |
| 333 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); | 338 MemOperand slot_operand = codegen()->EmitSlotSearch(slot, result_register()); |
| 334 __ movq(result_register(), slot_operand); | 339 __ movq(result_register(), slot_operand); |
| 335 } | 340 } |
| 336 | 341 |
| 337 | 342 |
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 536 void FullCodeGenerator::DoTest(Label* if_true, | 541 void FullCodeGenerator::DoTest(Label* if_true, |
| 537 Label* if_false, | 542 Label* if_false, |
| 538 Label* fall_through) { | 543 Label* fall_through) { |
| 539 // Emit the inlined tests assumed by the stub. | 544 // Emit the inlined tests assumed by the stub. |
| 540 __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex); | 545 __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex); |
| 541 __ j(equal, if_false); | 546 __ j(equal, if_false); |
| 542 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); | 547 __ CompareRoot(result_register(), Heap::kTrueValueRootIndex); |
| 543 __ j(equal, if_true); | 548 __ j(equal, if_true); |
| 544 __ CompareRoot(result_register(), Heap::kFalseValueRootIndex); | 549 __ CompareRoot(result_register(), Heap::kFalseValueRootIndex); |
| 545 __ j(equal, if_false); | 550 __ j(equal, if_false); |
| 546 ASSERT_EQ(0, kSmiTag); | 551 STATIC_ASSERT(kSmiTag == 0); |
| 547 __ SmiCompare(result_register(), Smi::FromInt(0)); | 552 __ Cmp(result_register(), Smi::FromInt(0)); |
| 548 __ j(equal, if_false); | 553 __ j(equal, if_false); |
| 549 Condition is_smi = masm_->CheckSmi(result_register()); | 554 Condition is_smi = masm_->CheckSmi(result_register()); |
| 550 __ j(is_smi, if_true); | 555 __ j(is_smi, if_true); |
| 551 | 556 |
| 552 // Call the ToBoolean stub for all other cases. | 557 // Call the ToBoolean stub for all other cases. |
| 553 ToBooleanStub stub; | 558 ToBooleanStub stub; |
| 554 __ push(result_register()); | 559 __ push(result_register()); |
| 555 __ CallStub(&stub); | 560 __ CallStub(&stub); |
| 556 __ testq(rax, rax); | 561 __ testq(rax, rax); |
| 557 | 562 |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 VisitForAccumulatorValue(function); | 731 VisitForAccumulatorValue(function); |
| 727 __ pop(rdx); | 732 __ pop(rdx); |
| 728 } else { | 733 } else { |
| 729 __ movq(rdx, rax); | 734 __ movq(rdx, rax); |
| 730 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); | 735 __ LoadRoot(rax, Heap::kTheHoleValueRootIndex); |
| 731 } | 736 } |
| 732 ASSERT(prop->key()->AsLiteral() != NULL && | 737 ASSERT(prop->key()->AsLiteral() != NULL && |
| 733 prop->key()->AsLiteral()->handle()->IsSmi()); | 738 prop->key()->AsLiteral()->handle()->IsSmi()); |
| 734 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 739 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 735 | 740 |
| 736 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 741 Handle<Code> ic(Builtins::builtin( |
| 742 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 743 : Builtins::KeyedStoreIC_Initialize)); |
| 737 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 744 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 738 } | 745 } |
| 739 } | 746 } |
| 740 } | 747 } |
| 741 | 748 |
| 742 | 749 |
| 743 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { | 750 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { |
| 744 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); | 751 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); |
| 745 } | 752 } |
| 746 | 753 |
| 747 | 754 |
| 748 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 755 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
| 749 // Call the runtime to declare the globals. | 756 // Call the runtime to declare the globals. |
| 750 __ push(rsi); // The context is the first argument. | 757 __ push(rsi); // The context is the first argument. |
| 751 __ Push(pairs); | 758 __ Push(pairs); |
| 752 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); | 759 __ Push(Smi::FromInt(is_eval() ? 1 : 0)); |
| 753 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 760 __ Push(Smi::FromInt(strict_mode_flag())); |
| 761 __ CallRuntime(Runtime::kDeclareGlobals, 4); |
| 754 // Return value is ignored. | 762 // Return value is ignored. |
| 755 } | 763 } |
| 756 | 764 |
| 757 | 765 |
| 758 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { | 766 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
| 759 Comment cmnt(masm_, "[ SwitchStatement"); | 767 Comment cmnt(masm_, "[ SwitchStatement"); |
| 760 Breakable nested_statement(this, stmt); | 768 Breakable nested_statement(this, stmt); |
| 761 SetStatementPosition(stmt); | 769 SetStatementPosition(stmt); |
| 762 | 770 |
| 763 // Keep the switch value on the stack until a case matches. | 771 // Keep the switch value on the stack until a case matches. |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 822 __ jmp(nested_statement.break_target()); | 830 __ jmp(nested_statement.break_target()); |
| 823 } else { | 831 } else { |
| 824 __ jmp(default_clause->body_target()->entry_label()); | 832 __ jmp(default_clause->body_target()->entry_label()); |
| 825 } | 833 } |
| 826 | 834 |
| 827 // Compile all the case bodies. | 835 // Compile all the case bodies. |
| 828 for (int i = 0; i < clauses->length(); i++) { | 836 for (int i = 0; i < clauses->length(); i++) { |
| 829 Comment cmnt(masm_, "[ Case body"); | 837 Comment cmnt(masm_, "[ Case body"); |
| 830 CaseClause* clause = clauses->at(i); | 838 CaseClause* clause = clauses->at(i); |
| 831 __ bind(clause->body_target()->entry_label()); | 839 __ bind(clause->body_target()->entry_label()); |
| 840 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS); |
| 832 VisitStatements(clause->statements()); | 841 VisitStatements(clause->statements()); |
| 833 } | 842 } |
| 834 | 843 |
| 835 __ bind(nested_statement.break_target()); | 844 __ bind(nested_statement.break_target()); |
| 836 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); | 845 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 837 } | 846 } |
| 838 | 847 |
| 839 | 848 |
| 840 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 849 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 841 Comment cmnt(masm_, "[ ForInStatement"); | 850 Comment cmnt(masm_, "[ ForInStatement"); |
| 842 SetStatementPosition(stmt); | 851 SetStatementPosition(stmt); |
| 843 | 852 |
| 844 Label loop, exit; | 853 Label loop, exit; |
| 845 ForIn loop_statement(this, stmt); | 854 ForIn loop_statement(this, stmt); |
| 846 increment_loop_depth(); | 855 increment_loop_depth(); |
| 847 | 856 |
| 848 // Get the object to enumerate over. Both SpiderMonkey and JSC | 857 // Get the object to enumerate over. Both SpiderMonkey and JSC |
| 849 // ignore null and undefined in contrast to the specification; see | 858 // ignore null and undefined in contrast to the specification; see |
| 850 // ECMA-262 section 12.6.4. | 859 // ECMA-262 section 12.6.4. |
| 851 VisitForAccumulatorValue(stmt->enumerable()); | 860 VisitForAccumulatorValue(stmt->enumerable()); |
| 852 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 861 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 853 __ j(equal, &exit); | 862 __ j(equal, &exit); |
| 854 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 863 Register null_value = rdi; |
| 864 __ LoadRoot(null_value, Heap::kNullValueRootIndex); |
| 865 __ cmpq(rax, null_value); |
| 855 __ j(equal, &exit); | 866 __ j(equal, &exit); |
| 856 | 867 |
| 857 // Convert the object to a JS object. | 868 // Convert the object to a JS object. |
| 858 Label convert, done_convert; | 869 Label convert, done_convert; |
| 859 __ JumpIfSmi(rax, &convert); | 870 __ JumpIfSmi(rax, &convert); |
| 860 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); | 871 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); |
| 861 __ j(above_equal, &done_convert); | 872 __ j(above_equal, &done_convert); |
| 862 __ bind(&convert); | 873 __ bind(&convert); |
| 863 __ push(rax); | 874 __ push(rax); |
| 864 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 875 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
| 865 __ bind(&done_convert); | 876 __ bind(&done_convert); |
| 866 __ push(rax); | 877 __ push(rax); |
| 867 | 878 |
| 868 // BUG(867): Check cache validity in generated code. This is a fast | 879 // Check cache validity in generated code. This is a fast case for |
| 869 // case for the JSObject::IsSimpleEnum cache validity checks. If we | 880 // the JSObject::IsSimpleEnum cache validity checks. If we cannot |
| 870 // cannot guarantee cache validity, call the runtime system to check | 881 // guarantee cache validity, call the runtime system to check cache |
| 871 // cache validity or get the property names in a fixed array. | 882 // validity or get the property names in a fixed array. |
| 883 Label next, call_runtime; |
| 884 Register empty_fixed_array_value = r8; |
| 885 __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex); |
| 886 Register empty_descriptor_array_value = r9; |
| 887 __ LoadRoot(empty_descriptor_array_value, |
| 888 Heap::kEmptyDescriptorArrayRootIndex); |
| 889 __ movq(rcx, rax); |
| 890 __ bind(&next); |
| 891 |
| 892 // Check that there are no elements. Register rcx contains the |
| 893 // current JS object we've reached through the prototype chain. |
| 894 __ cmpq(empty_fixed_array_value, |
| 895 FieldOperand(rcx, JSObject::kElementsOffset)); |
| 896 __ j(not_equal, &call_runtime); |
| 897 |
| 898 // Check that instance descriptors are not empty so that we can |
| 899 // check for an enum cache. Leave the map in rbx for the subsequent |
| 900 // prototype load. |
| 901 __ movq(rbx, FieldOperand(rcx, HeapObject::kMapOffset)); |
| 902 __ movq(rdx, FieldOperand(rbx, Map::kInstanceDescriptorsOffset)); |
| 903 __ cmpq(rdx, empty_descriptor_array_value); |
| 904 __ j(equal, &call_runtime); |
| 905 |
| 906 // Check that there is an enum cache in the non-empty instance |
| 907 // descriptors (rdx). This is the case if the next enumeration |
| 908 // index field does not contain a smi. |
| 909 __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumerationIndexOffset)); |
| 910 __ JumpIfSmi(rdx, &call_runtime); |
| 911 |
| 912 // For all objects but the receiver, check that the cache is empty. |
| 913 NearLabel check_prototype; |
| 914 __ cmpq(rcx, rax); |
| 915 __ j(equal, &check_prototype); |
| 916 __ movq(rdx, FieldOperand(rdx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 917 __ cmpq(rdx, empty_fixed_array_value); |
| 918 __ j(not_equal, &call_runtime); |
| 919 |
| 920 // Load the prototype from the map and loop if non-null. |
| 921 __ bind(&check_prototype); |
| 922 __ movq(rcx, FieldOperand(rbx, Map::kPrototypeOffset)); |
| 923 __ cmpq(rcx, null_value); |
| 924 __ j(not_equal, &next); |
| 925 |
| 926 // The enum cache is valid. Load the map of the object being |
| 927 // iterated over and use the cache for the iteration. |
| 928 NearLabel use_cache; |
| 929 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
| 930 __ jmp(&use_cache); |
| 872 | 931 |
| 873 // Get the set of properties to enumerate. | 932 // Get the set of properties to enumerate. |
| 933 __ bind(&call_runtime); |
| 874 __ push(rax); // Duplicate the enumerable object on the stack. | 934 __ push(rax); // Duplicate the enumerable object on the stack. |
| 875 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); | 935 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); |
| 876 | 936 |
| 877 // If we got a map from the runtime call, we can do a fast | 937 // If we got a map from the runtime call, we can do a fast |
| 878 // modification check. Otherwise, we got a fixed array, and we have | 938 // modification check. Otherwise, we got a fixed array, and we have |
| 879 // to do a slow check. | 939 // to do a slow check. |
| 880 NearLabel fixed_array; | 940 NearLabel fixed_array; |
| 881 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), | 941 __ CompareRoot(FieldOperand(rax, HeapObject::kMapOffset), |
| 882 Heap::kMetaMapRootIndex); | 942 Heap::kMetaMapRootIndex); |
| 883 __ j(not_equal, &fixed_array); | 943 __ j(not_equal, &fixed_array); |
| 884 | 944 |
| 885 // We got a map in register rax. Get the enumeration cache from it. | 945 // We got a map in register rax. Get the enumeration cache from it. |
| 946 __ bind(&use_cache); |
| 886 __ movq(rcx, FieldOperand(rax, Map::kInstanceDescriptorsOffset)); | 947 __ movq(rcx, FieldOperand(rax, Map::kInstanceDescriptorsOffset)); |
| 887 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset)); | 948 __ movq(rcx, FieldOperand(rcx, DescriptorArray::kEnumerationIndexOffset)); |
| 888 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 949 __ movq(rdx, FieldOperand(rcx, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 889 | 950 |
| 890 // Setup the four remaining stack slots. | 951 // Setup the four remaining stack slots. |
| 891 __ push(rax); // Map. | 952 __ push(rax); // Map. |
| 892 __ push(rdx); // Enumeration cache. | 953 __ push(rdx); // Enumeration cache. |
| 893 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset)); | 954 __ movq(rax, FieldOperand(rdx, FixedArray::kLengthOffset)); |
| 894 __ push(rax); // Enumeration cache length (as smi). | 955 __ push(rax); // Enumeration cache length (as smi). |
| 895 __ Push(Smi::FromInt(0)); // Initial index. | 956 __ Push(Smi::FromInt(0)); // Initial index. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 927 __ movq(rcx, Operand(rsp, 4 * kPointerSize)); | 988 __ movq(rcx, Operand(rsp, 4 * kPointerSize)); |
| 928 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset)); | 989 __ cmpq(rdx, FieldOperand(rcx, HeapObject::kMapOffset)); |
| 929 __ j(equal, &update_each); | 990 __ j(equal, &update_each); |
| 930 | 991 |
| 931 // Convert the entry to a string or null if it isn't a property | 992 // Convert the entry to a string or null if it isn't a property |
| 932 // anymore. If the property has been removed while iterating, we | 993 // anymore. If the property has been removed while iterating, we |
| 933 // just skip it. | 994 // just skip it. |
| 934 __ push(rcx); // Enumerable. | 995 __ push(rcx); // Enumerable. |
| 935 __ push(rbx); // Current entry. | 996 __ push(rbx); // Current entry. |
| 936 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); | 997 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); |
| 937 __ SmiCompare(rax, Smi::FromInt(0)); | 998 __ Cmp(rax, Smi::FromInt(0)); |
| 938 __ j(equal, loop_statement.continue_target()); | 999 __ j(equal, loop_statement.continue_target()); |
| 939 __ movq(rbx, rax); | 1000 __ movq(rbx, rax); |
| 940 | 1001 |
| 941 // Update the 'each' property or variable from the possibly filtered | 1002 // Update the 'each' property or variable from the possibly filtered |
| 942 // entry in register rbx. | 1003 // entry in register rbx. |
| 943 __ bind(&update_each); | 1004 __ bind(&update_each); |
| 944 __ movq(result_register(), rbx); | 1005 __ movq(result_register(), rbx); |
| 945 // Perform the assignment as if via '='. | 1006 // Perform the assignment as if via '='. |
| 946 { EffectContext context(this); | 1007 { EffectContext context(this); |
| 947 EmitAssignment(stmt->each(), stmt->AssignmentId()); | 1008 EmitAssignment(stmt->each(), stmt->AssignmentId()); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 964 | 1025 |
| 965 // Exit and decrement the loop depth. | 1026 // Exit and decrement the loop depth. |
| 966 __ bind(&exit); | 1027 __ bind(&exit); |
| 967 decrement_loop_depth(); | 1028 decrement_loop_depth(); |
| 968 } | 1029 } |
| 969 | 1030 |
| 970 | 1031 |
| 971 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, | 1032 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, |
| 972 bool pretenure) { | 1033 bool pretenure) { |
| 973 // Use the fast case closure allocation code that allocates in new | 1034 // Use the fast case closure allocation code that allocates in new |
| 974 // space for nested functions that don't need literals cloning. | 1035 // space for nested functions that don't need literals cloning. If |
| 975 if (scope()->is_function_scope() && | 1036 // we're running with the --always-opt or the --prepare-always-opt |
| 1037 // flag, we need to use the runtime function so that the new function |
| 1038 // we are creating here gets a chance to have its code optimized and |
| 1039 // doesn't just get a copy of the existing unoptimized code. |
| 1040 if (!FLAG_always_opt && |
| 1041 !FLAG_prepare_always_opt && |
| 1042 scope()->is_function_scope() && |
| 976 info->num_literals() == 0 && | 1043 info->num_literals() == 0 && |
| 977 !pretenure) { | 1044 !pretenure) { |
| 978 FastNewClosureStub stub; | 1045 FastNewClosureStub stub; |
| 979 __ Push(info); | 1046 __ Push(info); |
| 980 __ CallStub(&stub); | 1047 __ CallStub(&stub); |
| 981 } else { | 1048 } else { |
| 982 __ push(rsi); | 1049 __ push(rsi); |
| 983 __ Push(info); | 1050 __ Push(info); |
| 984 __ Push(pretenure ? Factory::true_value() : Factory::false_value()); | 1051 __ Push(pretenure ? Factory::true_value() : Factory::false_value()); |
| 985 __ CallRuntime(Runtime::kNewClosure, 3); | 1052 __ CallRuntime(Runtime::kNewClosure, 3); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1075 } | 1142 } |
| 1076 __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX)); | 1143 __ movq(temp, ContextOperand(context, Context::CLOSURE_INDEX)); |
| 1077 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); | 1144 __ movq(temp, FieldOperand(temp, JSFunction::kContextOffset)); |
| 1078 // Walk the rest of the chain without clobbering rsi. | 1145 // Walk the rest of the chain without clobbering rsi. |
| 1079 context = temp; | 1146 context = temp; |
| 1080 } | 1147 } |
| 1081 } | 1148 } |
| 1082 // Check that last extension is NULL. | 1149 // Check that last extension is NULL. |
| 1083 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); | 1150 __ cmpq(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0)); |
| 1084 __ j(not_equal, slow); | 1151 __ j(not_equal, slow); |
| 1085 __ movq(temp, ContextOperand(context, Context::FCONTEXT_INDEX)); | 1152 |
| 1086 return ContextOperand(temp, slot->index()); | 1153 // This function is used only for loads, not stores, so it's safe to |
| 1154 // return an rsi-based operand (the write barrier cannot be allowed to |
| 1155 // destroy the rsi register). |
| 1156 return ContextOperand(context, slot->index()); |
| 1087 } | 1157 } |
| 1088 | 1158 |
| 1089 | 1159 |
| 1090 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( | 1160 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( |
| 1091 Slot* slot, | 1161 Slot* slot, |
| 1092 TypeofState typeof_state, | 1162 TypeofState typeof_state, |
| 1093 Label* slow, | 1163 Label* slow, |
| 1094 Label* done) { | 1164 Label* done) { |
| 1095 // Generate fast-case code for variables that might be shadowed by | 1165 // Generate fast-case code for variables that might be shadowed by |
| 1096 // eval-introduced variables. Eval is used a lot without | 1166 // eval-introduced variables. Eval is used a lot without |
| (...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1326 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1396 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1327 } | 1397 } |
| 1328 break; | 1398 break; |
| 1329 } | 1399 } |
| 1330 // Fall through. | 1400 // Fall through. |
| 1331 case ObjectLiteral::Property::PROTOTYPE: | 1401 case ObjectLiteral::Property::PROTOTYPE: |
| 1332 __ push(Operand(rsp, 0)); // Duplicate receiver. | 1402 __ push(Operand(rsp, 0)); // Duplicate receiver. |
| 1333 VisitForStackValue(key); | 1403 VisitForStackValue(key); |
| 1334 VisitForStackValue(value); | 1404 VisitForStackValue(value); |
| 1335 if (property->emit_store()) { | 1405 if (property->emit_store()) { |
| 1336 __ CallRuntime(Runtime::kSetProperty, 3); | 1406 __ Push(Smi::FromInt(NONE)); // PropertyAttributes |
| 1407 __ CallRuntime(Runtime::kSetProperty, 4); |
| 1337 } else { | 1408 } else { |
| 1338 __ Drop(3); | 1409 __ Drop(3); |
| 1339 } | 1410 } |
| 1340 break; | 1411 break; |
| 1341 case ObjectLiteral::Property::SETTER: | 1412 case ObjectLiteral::Property::SETTER: |
| 1342 case ObjectLiteral::Property::GETTER: | 1413 case ObjectLiteral::Property::GETTER: |
| 1343 __ push(Operand(rsp, 0)); // Duplicate receiver. | 1414 __ push(Operand(rsp, 0)); // Duplicate receiver. |
| 1344 VisitForStackValue(key); | 1415 VisitForStackValue(key); |
| 1345 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? | 1416 __ Push(property->kind() == ObjectLiteral::Property::SETTER ? |
| 1346 Smi::FromInt(1) : | 1417 Smi::FromInt(1) : |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1502 } | 1573 } |
| 1503 } | 1574 } |
| 1504 | 1575 |
| 1505 // For property compound assignments we need another deoptimization | 1576 // For property compound assignments we need another deoptimization |
| 1506 // point after the property load. | 1577 // point after the property load. |
| 1507 if (property != NULL) { | 1578 if (property != NULL) { |
| 1508 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); | 1579 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); |
| 1509 } | 1580 } |
| 1510 | 1581 |
| 1511 Token::Value op = expr->binary_op(); | 1582 Token::Value op = expr->binary_op(); |
| 1512 ConstantOperand constant = ShouldInlineSmiCase(op) | 1583 __ push(rax); // Left operand goes on the stack. |
| 1513 ? GetConstantOperand(op, expr->target(), expr->value()) | 1584 VisitForAccumulatorValue(expr->value()); |
| 1514 : kNoConstants; | |
| 1515 ASSERT(constant == kRightConstant || constant == kNoConstants); | |
| 1516 if (constant == kNoConstants) { | |
| 1517 __ push(rax); // Left operand goes on the stack. | |
| 1518 VisitForAccumulatorValue(expr->value()); | |
| 1519 } | |
| 1520 | 1585 |
| 1521 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() | 1586 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() |
| 1522 ? OVERWRITE_RIGHT | 1587 ? OVERWRITE_RIGHT |
| 1523 : NO_OVERWRITE; | 1588 : NO_OVERWRITE; |
| 1524 SetSourcePosition(expr->position() + 1); | 1589 SetSourcePosition(expr->position() + 1); |
| 1525 AccumulatorValueContext context(this); | 1590 AccumulatorValueContext context(this); |
| 1526 if (ShouldInlineSmiCase(op)) { | 1591 if (ShouldInlineSmiCase(op)) { |
| 1527 EmitInlineSmiBinaryOp(expr, | 1592 EmitInlineSmiBinaryOp(expr, |
| 1528 op, | 1593 op, |
| 1529 mode, | 1594 mode, |
| 1530 expr->target(), | 1595 expr->target(), |
| 1531 expr->value(), | 1596 expr->value()); |
| 1532 constant); | |
| 1533 } else { | 1597 } else { |
| 1534 EmitBinaryOp(op, mode); | 1598 EmitBinaryOp(op, mode); |
| 1535 } | 1599 } |
| 1536 // Deoptimization point in case the binary operation may have side effects. | 1600 // Deoptimization point in case the binary operation may have side effects. |
| 1537 PrepareForBailout(expr->binary_operation(), TOS_REG); | 1601 PrepareForBailout(expr->binary_operation(), TOS_REG); |
| 1538 } else { | 1602 } else { |
| 1539 VisitForAccumulatorValue(expr->value()); | 1603 VisitForAccumulatorValue(expr->value()); |
| 1540 } | 1604 } |
| 1541 | 1605 |
| 1542 // Record source position before possible IC call. | 1606 // Record source position before possible IC call. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1573 SetSourcePosition(prop->position()); | 1637 SetSourcePosition(prop->position()); |
| 1574 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1638 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
| 1575 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1639 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1576 } | 1640 } |
| 1577 | 1641 |
| 1578 | 1642 |
| 1579 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, | 1643 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, |
| 1580 Token::Value op, | 1644 Token::Value op, |
| 1581 OverwriteMode mode, | 1645 OverwriteMode mode, |
| 1582 Expression* left, | 1646 Expression* left, |
| 1583 Expression* right, | 1647 Expression* right) { |
| 1584 ConstantOperand constant) { | |
| 1585 ASSERT(constant == kNoConstants); // Only handled case. | |
| 1586 | |
| 1587 // Do combined smi check of the operands. Left operand is on the | 1648 // Do combined smi check of the operands. Left operand is on the |
| 1588 // stack (popped into rdx). Right operand is in rax but moved into | 1649 // stack (popped into rdx). Right operand is in rax but moved into |
| 1589 // rcx to make the shifts easier. | 1650 // rcx to make the shifts easier. |
| 1590 NearLabel done, stub_call, smi_case; | 1651 NearLabel done, stub_call, smi_case; |
| 1591 __ pop(rdx); | 1652 __ pop(rdx); |
| 1592 __ movq(rcx, rax); | 1653 __ movq(rcx, rax); |
| 1593 __ or_(rax, rdx); | 1654 __ or_(rax, rdx); |
| 1594 JumpPatchSite patch_site(masm_); | 1655 JumpPatchSite patch_site(masm_); |
| 1595 patch_site.EmitJumpIfSmi(rax, &smi_case); | 1656 patch_site.EmitJumpIfSmi(rax, &smi_case); |
| 1596 | 1657 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1673 EffectContext context(this); | 1734 EffectContext context(this); |
| 1674 EmitVariableAssignment(var, Token::ASSIGN); | 1735 EmitVariableAssignment(var, Token::ASSIGN); |
| 1675 break; | 1736 break; |
| 1676 } | 1737 } |
| 1677 case NAMED_PROPERTY: { | 1738 case NAMED_PROPERTY: { |
| 1678 __ push(rax); // Preserve value. | 1739 __ push(rax); // Preserve value. |
| 1679 VisitForAccumulatorValue(prop->obj()); | 1740 VisitForAccumulatorValue(prop->obj()); |
| 1680 __ movq(rdx, rax); | 1741 __ movq(rdx, rax); |
| 1681 __ pop(rax); // Restore value. | 1742 __ pop(rax); // Restore value. |
| 1682 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1743 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 1683 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1744 Handle<Code> ic(Builtins::builtin( |
| 1745 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1746 : Builtins::StoreIC_Initialize)); |
| 1684 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1747 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1685 break; | 1748 break; |
| 1686 } | 1749 } |
| 1687 case KEYED_PROPERTY: { | 1750 case KEYED_PROPERTY: { |
| 1688 __ push(rax); // Preserve value. | 1751 __ push(rax); // Preserve value. |
| 1689 if (prop->is_synthetic()) { | 1752 if (prop->is_synthetic()) { |
| 1690 ASSERT(prop->obj()->AsVariableProxy() != NULL); | 1753 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 1691 ASSERT(prop->key()->AsLiteral() != NULL); | 1754 ASSERT(prop->key()->AsLiteral() != NULL); |
| 1692 { AccumulatorValueContext for_object(this); | 1755 { AccumulatorValueContext for_object(this); |
| 1693 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); | 1756 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); |
| 1694 } | 1757 } |
| 1695 __ movq(rdx, rax); | 1758 __ movq(rdx, rax); |
| 1696 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1759 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 1697 } else { | 1760 } else { |
| 1698 VisitForStackValue(prop->obj()); | 1761 VisitForStackValue(prop->obj()); |
| 1699 VisitForAccumulatorValue(prop->key()); | 1762 VisitForAccumulatorValue(prop->key()); |
| 1700 __ movq(rcx, rax); | 1763 __ movq(rcx, rax); |
| 1701 __ pop(rdx); | 1764 __ pop(rdx); |
| 1702 } | 1765 } |
| 1703 __ pop(rax); // Restore value. | 1766 __ pop(rax); // Restore value. |
| 1704 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1767 Handle<Code> ic(Builtins::builtin( |
| 1768 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 1769 : Builtins::KeyedStoreIC_Initialize)); |
| 1705 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1770 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1706 break; | 1771 break; |
| 1707 } | 1772 } |
| 1708 } | 1773 } |
| 1709 PrepareForBailoutForId(bailout_ast_id, TOS_REG); | 1774 PrepareForBailoutForId(bailout_ast_id, TOS_REG); |
| 1710 context()->Plug(rax); | 1775 context()->Plug(rax); |
| 1711 } | 1776 } |
| 1712 | 1777 |
| 1713 | 1778 |
| 1714 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 1779 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 1715 Token::Value op) { | 1780 Token::Value op) { |
| 1716 // Left-hand sides that rewrite to explicit property accesses do not reach | 1781 // Left-hand sides that rewrite to explicit property accesses do not reach |
| 1717 // here. | 1782 // here. |
| 1718 ASSERT(var != NULL); | 1783 ASSERT(var != NULL); |
| 1719 ASSERT(var->is_global() || var->AsSlot() != NULL); | 1784 ASSERT(var->is_global() || var->AsSlot() != NULL); |
| 1720 | 1785 |
| 1721 if (var->is_global()) { | 1786 if (var->is_global()) { |
| 1722 ASSERT(!var->is_this()); | 1787 ASSERT(!var->is_this()); |
| 1723 // Assignment to a global variable. Use inline caching for the | 1788 // Assignment to a global variable. Use inline caching for the |
| 1724 // assignment. Right-hand-side value is passed in rax, variable name in | 1789 // assignment. Right-hand-side value is passed in rax, variable name in |
| 1725 // rcx, and the global object on the stack. | 1790 // rcx, and the global object on the stack. |
| 1726 __ Move(rcx, var->name()); | 1791 __ Move(rcx, var->name()); |
| 1727 __ movq(rdx, GlobalObjectOperand()); | 1792 __ movq(rdx, GlobalObjectOperand()); |
| 1728 Handle<Code> ic(Builtins::builtin(is_strict() | 1793 Handle<Code> ic(Builtins::builtin( |
| 1729 ? Builtins::StoreIC_Initialize_Strict | 1794 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1730 : Builtins::StoreIC_Initialize)); | 1795 : Builtins::StoreIC_Initialize)); |
| 1731 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); | 1796 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); |
| 1732 | 1797 |
| 1733 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { | 1798 } else if (op == Token::INIT_CONST) { |
| 1734 // Perform the assignment for non-const variables and for initialization | 1799 // Like var declarations, const declarations are hoisted to function |
| 1735 // of const variables. Const assignments are simply skipped. | 1800 // scope. However, unlike var initializers, const initializers are able |
| 1736 Label done; | 1801 // to drill a hole to that function context, even from inside a 'with' |
| 1802 // context. We thus bypass the normal static scope lookup. |
| 1803 Slot* slot = var->AsSlot(); |
| 1804 Label skip; |
| 1805 switch (slot->type()) { |
| 1806 case Slot::PARAMETER: |
| 1807 // No const parameters. |
| 1808 UNREACHABLE(); |
| 1809 break; |
| 1810 case Slot::LOCAL: |
| 1811 __ movq(rdx, Operand(rbp, SlotOffset(slot))); |
| 1812 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 1813 __ j(not_equal, &skip); |
| 1814 __ movq(Operand(rbp, SlotOffset(slot)), rax); |
| 1815 break; |
| 1816 case Slot::CONTEXT: { |
| 1817 __ movq(rcx, ContextOperand(rsi, Context::FCONTEXT_INDEX)); |
| 1818 __ movq(rdx, ContextOperand(rcx, slot->index())); |
| 1819 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); |
| 1820 __ j(not_equal, &skip); |
| 1821 __ movq(ContextOperand(rcx, slot->index()), rax); |
| 1822 int offset = Context::SlotOffset(slot->index()); |
| 1823 __ movq(rdx, rax); // Preserve the stored value in eax. |
| 1824 __ RecordWrite(rcx, offset, rdx, rbx); |
| 1825 break; |
| 1826 } |
| 1827 case Slot::LOOKUP: |
| 1828 __ push(rax); |
| 1829 __ push(rsi); |
| 1830 __ Push(var->name()); |
| 1831 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 1832 break; |
| 1833 } |
| 1834 __ bind(&skip); |
| 1835 |
| 1836 } else if (var->mode() != Variable::CONST) { |
| 1837 // Perform the assignment for non-const variables. Const assignments |
| 1838 // are simply skipped. |
| 1737 Slot* slot = var->AsSlot(); | 1839 Slot* slot = var->AsSlot(); |
| 1738 switch (slot->type()) { | 1840 switch (slot->type()) { |
| 1739 case Slot::PARAMETER: | 1841 case Slot::PARAMETER: |
| 1740 case Slot::LOCAL: | 1842 case Slot::LOCAL: |
| 1741 if (op == Token::INIT_CONST) { | |
| 1742 // Detect const reinitialization by checking for the hole value. | |
| 1743 __ movq(rdx, Operand(rbp, SlotOffset(slot))); | |
| 1744 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | |
| 1745 __ j(not_equal, &done); | |
| 1746 } | |
| 1747 // Perform the assignment. | 1843 // Perform the assignment. |
| 1748 __ movq(Operand(rbp, SlotOffset(slot)), rax); | 1844 __ movq(Operand(rbp, SlotOffset(slot)), rax); |
| 1749 break; | 1845 break; |
| 1750 | 1846 |
| 1751 case Slot::CONTEXT: { | 1847 case Slot::CONTEXT: { |
| 1752 MemOperand target = EmitSlotSearch(slot, rcx); | 1848 MemOperand target = EmitSlotSearch(slot, rcx); |
| 1753 if (op == Token::INIT_CONST) { | |
| 1754 // Detect const reinitialization by checking for the hole value. | |
| 1755 __ movq(rdx, target); | |
| 1756 __ CompareRoot(rdx, Heap::kTheHoleValueRootIndex); | |
| 1757 __ j(not_equal, &done); | |
| 1758 } | |
| 1759 // Perform the assignment and issue the write barrier. | 1849 // Perform the assignment and issue the write barrier. |
| 1760 __ movq(target, rax); | 1850 __ movq(target, rax); |
| 1761 | 1851 |
| 1762 // The value of the assignment is in rax. RecordWrite clobbers its | 1852 // The value of the assignment is in rax. RecordWrite clobbers its |
| 1763 // register arguments. | 1853 // register arguments. |
| 1764 __ movq(rdx, rax); | 1854 __ movq(rdx, rax); |
| 1765 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 1855 int offset = Context::SlotOffset(slot->index()); |
| 1766 __ RecordWrite(rcx, offset, rdx, rbx, kDontSaveFPRegs); | 1856 __ RecordWrite(rcx, offset, rdx, rbx, kDontSaveFPRegs); |
| 1767 break; | 1857 break; |
| 1768 } | 1858 } |
| 1769 | 1859 |
| 1770 case Slot::LOOKUP: | 1860 case Slot::LOOKUP: |
| 1771 // Call the runtime for the assignment. The runtime will ignore | 1861 // Call the runtime for the assignment. |
| 1772 // const reinitialization. | |
| 1773 __ push(rax); // Value. | 1862 __ push(rax); // Value. |
| 1774 __ push(rsi); // Context. | 1863 __ push(rsi); // Context. |
| 1775 __ Push(var->name()); | 1864 __ Push(var->name()); |
| 1776 if (op == Token::INIT_CONST) { | 1865 __ Push(Smi::FromInt(strict_mode_flag())); |
| 1777 // The runtime will ignore const redeclaration. | 1866 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
| 1778 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
| 1779 } else { | |
| 1780 __ CallRuntime(Runtime::kStoreContextSlot, 3); | |
| 1781 } | |
| 1782 break; | 1867 break; |
| 1783 } | 1868 } |
| 1784 __ bind(&done); | |
| 1785 } | 1869 } |
| 1786 } | 1870 } |
| 1787 | 1871 |
| 1788 | 1872 |
| 1789 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 1873 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 1790 // Assignment to a property, using a named store IC. | 1874 // Assignment to a property, using a named store IC. |
| 1791 Property* prop = expr->target()->AsProperty(); | 1875 Property* prop = expr->target()->AsProperty(); |
| 1792 ASSERT(prop != NULL); | 1876 ASSERT(prop != NULL); |
| 1793 ASSERT(prop->key()->AsLiteral() != NULL); | 1877 ASSERT(prop->key()->AsLiteral() != NULL); |
| 1794 | 1878 |
| 1795 // If the assignment starts a block of assignments to the same object, | 1879 // If the assignment starts a block of assignments to the same object, |
| 1796 // change to slow case to avoid the quadratic behavior of repeatedly | 1880 // change to slow case to avoid the quadratic behavior of repeatedly |
| 1797 // adding fast properties. | 1881 // adding fast properties. |
| 1798 if (expr->starts_initialization_block()) { | 1882 if (expr->starts_initialization_block()) { |
| 1799 __ push(result_register()); | 1883 __ push(result_register()); |
| 1800 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value. | 1884 __ push(Operand(rsp, kPointerSize)); // Receiver is now under value. |
| 1801 __ CallRuntime(Runtime::kToSlowProperties, 1); | 1885 __ CallRuntime(Runtime::kToSlowProperties, 1); |
| 1802 __ pop(result_register()); | 1886 __ pop(result_register()); |
| 1803 } | 1887 } |
| 1804 | 1888 |
| 1805 // Record source code position before IC call. | 1889 // Record source code position before IC call. |
| 1806 SetSourcePosition(expr->position()); | 1890 SetSourcePosition(expr->position()); |
| 1807 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 1891 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 1808 if (expr->ends_initialization_block()) { | 1892 if (expr->ends_initialization_block()) { |
| 1809 __ movq(rdx, Operand(rsp, 0)); | 1893 __ movq(rdx, Operand(rsp, 0)); |
| 1810 } else { | 1894 } else { |
| 1811 __ pop(rdx); | 1895 __ pop(rdx); |
| 1812 } | 1896 } |
| 1813 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 1897 Handle<Code> ic(Builtins::builtin( |
| 1898 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 1899 : Builtins::StoreIC_Initialize)); |
| 1814 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1900 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1815 | 1901 |
| 1816 // If the assignment ends an initialization block, revert to fast case. | 1902 // If the assignment ends an initialization block, revert to fast case. |
| 1817 if (expr->ends_initialization_block()) { | 1903 if (expr->ends_initialization_block()) { |
| 1818 __ push(rax); // Result of assignment, saved even if not needed. | 1904 __ push(rax); // Result of assignment, saved even if not needed. |
| 1819 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. | 1905 __ push(Operand(rsp, kPointerSize)); // Receiver is under value. |
| 1820 __ CallRuntime(Runtime::kToFastProperties, 1); | 1906 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1821 __ pop(rax); | 1907 __ pop(rax); |
| 1822 __ Drop(1); | 1908 __ Drop(1); |
| 1823 } | 1909 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1841 } | 1927 } |
| 1842 | 1928 |
| 1843 __ pop(rcx); | 1929 __ pop(rcx); |
| 1844 if (expr->ends_initialization_block()) { | 1930 if (expr->ends_initialization_block()) { |
| 1845 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later. | 1931 __ movq(rdx, Operand(rsp, 0)); // Leave receiver on the stack for later. |
| 1846 } else { | 1932 } else { |
| 1847 __ pop(rdx); | 1933 __ pop(rdx); |
| 1848 } | 1934 } |
| 1849 // Record source code position before IC call. | 1935 // Record source code position before IC call. |
| 1850 SetSourcePosition(expr->position()); | 1936 SetSourcePosition(expr->position()); |
| 1851 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 1937 Handle<Code> ic(Builtins::builtin( |
| 1938 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 1939 : Builtins::KeyedStoreIC_Initialize)); |
| 1852 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 1940 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 1853 | 1941 |
| 1854 // If the assignment ends an initialization block, revert to fast case. | 1942 // If the assignment ends an initialization block, revert to fast case. |
| 1855 if (expr->ends_initialization_block()) { | 1943 if (expr->ends_initialization_block()) { |
| 1856 __ pop(rdx); | 1944 __ pop(rdx); |
| 1857 __ push(rax); // Result of assignment, saved even if not needed. | 1945 __ push(rax); // Result of assignment, saved even if not needed. |
| 1858 __ push(rdx); | 1946 __ push(rdx); |
| 1859 __ CallRuntime(Runtime::kToFastProperties, 1); | 1947 __ CallRuntime(Runtime::kToFastProperties, 1); |
| 1860 __ pop(rax); | 1948 __ pop(rax); |
| 1861 } | 1949 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1957 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 2045 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| 1958 __ CallStub(&stub); | 2046 __ CallStub(&stub); |
| 1959 RecordJSReturnSite(expr); | 2047 RecordJSReturnSite(expr); |
| 1960 // Restore context register. | 2048 // Restore context register. |
| 1961 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 2049 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 1962 // Discard the function left on TOS. | 2050 // Discard the function left on TOS. |
| 1963 context()->DropAndPlug(1, rax); | 2051 context()->DropAndPlug(1, rax); |
| 1964 } | 2052 } |
| 1965 | 2053 |
| 1966 | 2054 |
| 2055 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, |
| 2056 int arg_count) { |
| 2057 // Push copy of the first argument or undefined if it doesn't exist. |
| 2058 if (arg_count > 0) { |
| 2059 __ push(Operand(rsp, arg_count * kPointerSize)); |
| 2060 } else { |
| 2061 __ PushRoot(Heap::kUndefinedValueRootIndex); |
| 2062 } |
| 2063 |
| 2064 // Push the receiver of the enclosing function and do runtime call. |
| 2065 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize)); |
| 2066 |
| 2067 // Push the strict mode flag. |
| 2068 __ Push(Smi::FromInt(strict_mode_flag())); |
| 2069 |
| 2070 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP |
| 2071 ? Runtime::kResolvePossiblyDirectEvalNoLookup |
| 2072 : Runtime::kResolvePossiblyDirectEval, 4); |
| 2073 } |
| 2074 |
| 2075 |
| 1967 void FullCodeGenerator::VisitCall(Call* expr) { | 2076 void FullCodeGenerator::VisitCall(Call* expr) { |
| 1968 #ifdef DEBUG | 2077 #ifdef DEBUG |
| 1969 // We want to verify that RecordJSReturnSite gets called on all paths | 2078 // We want to verify that RecordJSReturnSite gets called on all paths |
| 1970 // through this function. Avoid early returns. | 2079 // through this function. Avoid early returns. |
| 1971 expr->return_is_recorded_ = false; | 2080 expr->return_is_recorded_ = false; |
| 1972 #endif | 2081 #endif |
| 1973 | 2082 |
| 1974 Comment cmnt(masm_, "[ Call"); | 2083 Comment cmnt(masm_, "[ Call"); |
| 1975 Expression* fun = expr->expression(); | 2084 Expression* fun = expr->expression(); |
| 1976 Variable* var = fun->AsVariableProxy()->AsVariable(); | 2085 Variable* var = fun->AsVariableProxy()->AsVariable(); |
| 1977 | 2086 |
| 1978 if (var != NULL && var->is_possibly_eval()) { | 2087 if (var != NULL && var->is_possibly_eval()) { |
| 1979 // In a call to eval, we first call %ResolvePossiblyDirectEval to | 2088 // In a call to eval, we first call %ResolvePossiblyDirectEval to |
| 1980 // resolve the function we need to call and the receiver of the | 2089 // resolve the function we need to call and the receiver of the |
| 1981 // call. Then we call the resolved function using the given | 2090 // call. Then we call the resolved function using the given |
| 1982 // arguments. | 2091 // arguments. |
| 1983 ZoneList<Expression*>* args = expr->arguments(); | 2092 ZoneList<Expression*>* args = expr->arguments(); |
| 1984 int arg_count = args->length(); | 2093 int arg_count = args->length(); |
| 1985 { PreservePositionScope pos_scope(masm()->positions_recorder()); | 2094 { PreservePositionScope pos_scope(masm()->positions_recorder()); |
| 1986 VisitForStackValue(fun); | 2095 VisitForStackValue(fun); |
| 1987 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot. | 2096 __ PushRoot(Heap::kUndefinedValueRootIndex); // Reserved receiver slot. |
| 1988 | 2097 |
| 1989 // Push the arguments. | 2098 // Push the arguments. |
| 1990 for (int i = 0; i < arg_count; i++) { | 2099 for (int i = 0; i < arg_count; i++) { |
| 1991 VisitForStackValue(args->at(i)); | 2100 VisitForStackValue(args->at(i)); |
| 1992 } | 2101 } |
| 1993 | 2102 |
| 1994 // Push copy of the function - found below the arguments. | 2103 // If we know that eval can only be shadowed by eval-introduced |
| 1995 __ push(Operand(rsp, (arg_count + 1) * kPointerSize)); | 2104 // variables we attempt to load the global eval function directly |
| 1996 | 2105 // in generated code. If we succeed, there is no need to perform a |
| 1997 // Push copy of the first argument or undefined if it doesn't exist. | 2106 // context lookup in the runtime system. |
| 1998 if (arg_count > 0) { | 2107 Label done; |
| 1999 __ push(Operand(rsp, arg_count * kPointerSize)); | 2108 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) { |
| 2000 } else { | 2109 Label slow; |
| 2001 __ PushRoot(Heap::kUndefinedValueRootIndex); | 2110 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(), |
| 2111 NOT_INSIDE_TYPEOF, |
| 2112 &slow); |
| 2113 // Push the function and resolve eval. |
| 2114 __ push(rax); |
| 2115 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); |
| 2116 __ jmp(&done); |
| 2117 __ bind(&slow); |
| 2002 } | 2118 } |
| 2003 | 2119 |
| 2004 // Push the receiver of the enclosing function and do runtime call. | 2120 // Push copy of the function (found below the arguments) and |
| 2005 __ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize)); | 2121 // resolve eval. |
| 2006 // Push the strict mode flag. | 2122 __ push(Operand(rsp, (arg_count + 1) * kPointerSize)); |
| 2007 __ Push(Smi::FromInt(strict_mode_flag())); | 2123 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count); |
| 2008 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4); | 2124 if (done.is_linked()) { |
| 2125 __ bind(&done); |
| 2126 } |
| 2009 | 2127 |
| 2010 // The runtime call returns a pair of values in rax (function) and | 2128 // The runtime call returns a pair of values in rax (function) and |
| 2011 // rdx (receiver). Touch up the stack with the right values. | 2129 // rdx (receiver). Touch up the stack with the right values. |
| 2012 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx); | 2130 __ movq(Operand(rsp, (arg_count + 0) * kPointerSize), rdx); |
| 2013 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax); | 2131 __ movq(Operand(rsp, (arg_count + 1) * kPointerSize), rax); |
| 2014 } | 2132 } |
| 2015 // Record source position for debugger. | 2133 // Record source position for debugger. |
| 2016 SetSourcePosition(expr->position()); | 2134 SetSourcePosition(expr->position()); |
| 2017 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; | 2135 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; |
| 2018 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); | 2136 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2378 Label* if_false = NULL; | 2496 Label* if_false = NULL; |
| 2379 Label* fall_through = NULL; | 2497 Label* fall_through = NULL; |
| 2380 context()->PrepareTest(&materialize_true, &materialize_false, | 2498 context()->PrepareTest(&materialize_true, &materialize_false, |
| 2381 &if_true, &if_false, &fall_through); | 2499 &if_true, &if_false, &fall_through); |
| 2382 | 2500 |
| 2383 // Get the frame pointer for the calling frame. | 2501 // Get the frame pointer for the calling frame. |
| 2384 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 2502 __ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 2385 | 2503 |
| 2386 // Skip the arguments adaptor frame if it exists. | 2504 // Skip the arguments adaptor frame if it exists. |
| 2387 Label check_frame_marker; | 2505 Label check_frame_marker; |
| 2388 __ SmiCompare(Operand(rax, StandardFrameConstants::kContextOffset), | 2506 __ Cmp(Operand(rax, StandardFrameConstants::kContextOffset), |
| 2389 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2507 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2390 __ j(not_equal, &check_frame_marker); | 2508 __ j(not_equal, &check_frame_marker); |
| 2391 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); | 2509 __ movq(rax, Operand(rax, StandardFrameConstants::kCallerFPOffset)); |
| 2392 | 2510 |
| 2393 // Check the marker in the calling frame. | 2511 // Check the marker in the calling frame. |
| 2394 __ bind(&check_frame_marker); | 2512 __ bind(&check_frame_marker); |
| 2395 __ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset), | 2513 __ Cmp(Operand(rax, StandardFrameConstants::kMarkerOffset), |
| 2396 Smi::FromInt(StackFrame::CONSTRUCT)); | 2514 Smi::FromInt(StackFrame::CONSTRUCT)); |
| 2397 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 2515 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2398 Split(equal, if_true, if_false, fall_through); | 2516 Split(equal, if_true, if_false, fall_through); |
| 2399 | 2517 |
| 2400 context()->Plug(if_true, if_false); | 2518 context()->Plug(if_true, if_false); |
| 2401 } | 2519 } |
| 2402 | 2520 |
| 2403 | 2521 |
| 2404 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { | 2522 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) { |
| 2405 ASSERT(args->length() == 2); | 2523 ASSERT(args->length() == 2); |
| 2406 | 2524 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2440 | 2558 |
| 2441 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { | 2559 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) { |
| 2442 ASSERT(args->length() == 0); | 2560 ASSERT(args->length() == 0); |
| 2443 | 2561 |
| 2444 NearLabel exit; | 2562 NearLabel exit; |
| 2445 // Get the number of formal parameters. | 2563 // Get the number of formal parameters. |
| 2446 __ Move(rax, Smi::FromInt(scope()->num_parameters())); | 2564 __ Move(rax, Smi::FromInt(scope()->num_parameters())); |
| 2447 | 2565 |
| 2448 // Check if the calling frame is an arguments adaptor frame. | 2566 // Check if the calling frame is an arguments adaptor frame. |
| 2449 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 2567 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 2450 __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset), | 2568 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset), |
| 2451 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2569 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2452 __ j(not_equal, &exit); | 2570 __ j(not_equal, &exit); |
| 2453 | 2571 |
| 2454 // Arguments adaptor case: Read the arguments length from the | 2572 // Arguments adaptor case: Read the arguments length from the |
| 2455 // adaptor frame. | 2573 // adaptor frame. |
| 2456 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 2574 __ movq(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
| 2457 | 2575 |
| 2458 __ bind(&exit); | 2576 __ bind(&exit); |
| 2459 if (FLAG_debug_code) __ AbortIfNotSmi(rax); | 2577 if (FLAG_debug_code) __ AbortIfNotSmi(rax); |
| 2460 context()->Plug(rax); | 2578 context()->Plug(rax); |
| 2461 } | 2579 } |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2615 __ bind(&done); | 2733 __ bind(&done); |
| 2616 context()->Plug(rax); | 2734 context()->Plug(rax); |
| 2617 } | 2735 } |
| 2618 | 2736 |
| 2619 | 2737 |
| 2620 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) { | 2738 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) { |
| 2621 // Load the arguments on the stack and call the runtime function. | 2739 // Load the arguments on the stack and call the runtime function. |
| 2622 ASSERT(args->length() == 2); | 2740 ASSERT(args->length() == 2); |
| 2623 VisitForStackValue(args->at(0)); | 2741 VisitForStackValue(args->at(0)); |
| 2624 VisitForStackValue(args->at(1)); | 2742 VisitForStackValue(args->at(1)); |
| 2625 __ CallRuntime(Runtime::kMath_pow, 2); | 2743 MathPowStub stub; |
| 2744 __ CallStub(&stub); |
| 2626 context()->Plug(rax); | 2745 context()->Plug(rax); |
| 2627 } | 2746 } |
| 2628 | 2747 |
| 2629 | 2748 |
| 2630 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { | 2749 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { |
| 2631 ASSERT(args->length() == 2); | 2750 ASSERT(args->length() == 2); |
| 2632 | 2751 |
| 2633 VisitForStackValue(args->at(0)); // Load the object. | 2752 VisitForStackValue(args->at(0)); // Load the object. |
| 2634 VisitForAccumulatorValue(args->at(1)); // Load the value. | 2753 VisitForAccumulatorValue(args->at(1)); // Load the value. |
| 2635 __ pop(rbx); // rax = value. rbx = object. | 2754 __ pop(rbx); // rax = value. rbx = object. |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2799 VisitForStackValue(args->at(1)); | 2918 VisitForStackValue(args->at(1)); |
| 2800 | 2919 |
| 2801 StringCompareStub stub; | 2920 StringCompareStub stub; |
| 2802 __ CallStub(&stub); | 2921 __ CallStub(&stub); |
| 2803 context()->Plug(rax); | 2922 context()->Plug(rax); |
| 2804 } | 2923 } |
| 2805 | 2924 |
| 2806 | 2925 |
| 2807 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) { | 2926 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) { |
| 2808 // Load the argument on the stack and call the stub. | 2927 // Load the argument on the stack and call the stub. |
| 2809 TranscendentalCacheStub stub(TranscendentalCache::SIN); | 2928 TranscendentalCacheStub stub(TranscendentalCache::SIN, |
| 2929 TranscendentalCacheStub::TAGGED); |
| 2810 ASSERT(args->length() == 1); | 2930 ASSERT(args->length() == 1); |
| 2811 VisitForStackValue(args->at(0)); | 2931 VisitForStackValue(args->at(0)); |
| 2812 __ CallStub(&stub); | 2932 __ CallStub(&stub); |
| 2813 context()->Plug(rax); | 2933 context()->Plug(rax); |
| 2814 } | 2934 } |
| 2815 | 2935 |
| 2816 | 2936 |
| 2817 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) { | 2937 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) { |
| 2818 // Load the argument on the stack and call the stub. | 2938 // Load the argument on the stack and call the stub. |
| 2819 TranscendentalCacheStub stub(TranscendentalCache::COS); | 2939 TranscendentalCacheStub stub(TranscendentalCache::COS, |
| 2940 TranscendentalCacheStub::TAGGED); |
| 2820 ASSERT(args->length() == 1); | 2941 ASSERT(args->length() == 1); |
| 2821 VisitForStackValue(args->at(0)); | 2942 VisitForStackValue(args->at(0)); |
| 2822 __ CallStub(&stub); | 2943 __ CallStub(&stub); |
| 2823 context()->Plug(rax); | 2944 context()->Plug(rax); |
| 2824 } | 2945 } |
| 2825 | 2946 |
| 2826 | 2947 |
| 2827 void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) { | 2948 void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) { |
| 2828 // Load the argument on the stack and call the stub. | 2949 // Load the argument on the stack and call the stub. |
| 2829 TranscendentalCacheStub stub(TranscendentalCache::LOG); | 2950 TranscendentalCacheStub stub(TranscendentalCache::LOG, |
| 2951 TranscendentalCacheStub::TAGGED); |
| 2830 ASSERT(args->length() == 1); | 2952 ASSERT(args->length() == 1); |
| 2831 VisitForStackValue(args->at(0)); | 2953 VisitForStackValue(args->at(0)); |
| 2832 __ CallStub(&stub); | 2954 __ CallStub(&stub); |
| 2833 context()->Plug(rax); | 2955 context()->Plug(rax); |
| 2834 } | 2956 } |
| 2835 | 2957 |
| 2836 | 2958 |
| 2837 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) { | 2959 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) { |
| 2838 // Load the argument on the stack and call the runtime function. | 2960 // Load the argument on the stack and call the runtime function. |
| 2839 ASSERT(args->length() == 1); | 2961 ASSERT(args->length() == 1); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2871 __ CallStub(&stub); | 2993 __ CallStub(&stub); |
| 2872 context()->Plug(rax); | 2994 context()->Plug(rax); |
| 2873 } | 2995 } |
| 2874 | 2996 |
| 2875 | 2997 |
| 2876 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) { | 2998 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) { |
| 2877 ASSERT(args->length() == 3); | 2999 ASSERT(args->length() == 3); |
| 2878 VisitForStackValue(args->at(0)); | 3000 VisitForStackValue(args->at(0)); |
| 2879 VisitForStackValue(args->at(1)); | 3001 VisitForStackValue(args->at(1)); |
| 2880 VisitForStackValue(args->at(2)); | 3002 VisitForStackValue(args->at(2)); |
| 3003 Label done; |
| 3004 Label slow_case; |
| 3005 Register object = rax; |
| 3006 Register index_1 = rbx; |
| 3007 Register index_2 = rcx; |
| 3008 Register elements = rdi; |
| 3009 Register temp = rdx; |
| 3010 __ movq(object, Operand(rsp, 2 * kPointerSize)); |
| 3011 // Fetch the map and check if array is in fast case. |
| 3012 // Check that object doesn't require security checks and |
| 3013 // has no indexed interceptor. |
| 3014 __ CmpObjectType(object, JS_ARRAY_TYPE, temp); |
| 3015 __ j(not_equal, &slow_case); |
| 3016 __ testb(FieldOperand(temp, Map::kBitFieldOffset), |
| 3017 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask)); |
| 3018 __ j(not_zero, &slow_case); |
| 3019 |
| 3020 // Check the object's elements are in fast case and writable. |
| 3021 __ movq(elements, FieldOperand(object, JSObject::kElementsOffset)); |
| 3022 __ CompareRoot(FieldOperand(elements, HeapObject::kMapOffset), |
| 3023 Heap::kFixedArrayMapRootIndex); |
| 3024 __ j(not_equal, &slow_case); |
| 3025 |
| 3026 // Check that both indices are smis. |
| 3027 __ movq(index_1, Operand(rsp, 1 * kPointerSize)); |
| 3028 __ movq(index_2, Operand(rsp, 0 * kPointerSize)); |
| 3029 __ JumpIfNotBothSmi(index_1, index_2, &slow_case); |
| 3030 |
| 3031 // Check that both indices are valid. |
| 3032 // The JSArray length field is a smi since the array is in fast case mode. |
| 3033 __ movq(temp, FieldOperand(object, JSArray::kLengthOffset)); |
| 3034 __ SmiCompare(temp, index_1); |
| 3035 __ j(below_equal, &slow_case); |
| 3036 __ SmiCompare(temp, index_2); |
| 3037 __ j(below_equal, &slow_case); |
| 3038 |
| 3039 __ SmiToInteger32(index_1, index_1); |
| 3040 __ SmiToInteger32(index_2, index_2); |
| 3041 // Bring addresses into index1 and index2. |
| 3042 __ lea(index_1, FieldOperand(elements, index_1, times_pointer_size, |
| 3043 FixedArray::kHeaderSize)); |
| 3044 __ lea(index_2, FieldOperand(elements, index_2, times_pointer_size, |
| 3045 FixedArray::kHeaderSize)); |
| 3046 |
| 3047 // Swap elements. Use object and temp as scratch registers. |
| 3048 __ movq(object, Operand(index_1, 0)); |
| 3049 __ movq(temp, Operand(index_2, 0)); |
| 3050 __ movq(Operand(index_2, 0), object); |
| 3051 __ movq(Operand(index_1, 0), temp); |
| 3052 |
| 3053 Label new_space; |
| 3054 __ InNewSpace(elements, temp, equal, &new_space); |
| 3055 |
| 3056 __ movq(object, elements); |
| 3057 __ RecordWriteHelper(object, index_1, temp); |
| 3058 __ RecordWriteHelper(elements, index_2, temp); |
| 3059 |
| 3060 __ bind(&new_space); |
| 3061 // We are done. Drop elements from the stack, and return undefined. |
| 3062 __ addq(rsp, Immediate(3 * kPointerSize)); |
| 3063 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 3064 __ jmp(&done); |
| 3065 |
| 3066 __ bind(&slow_case); |
| 2881 __ CallRuntime(Runtime::kSwapElements, 3); | 3067 __ CallRuntime(Runtime::kSwapElements, 3); |
| 3068 |
| 3069 __ bind(&done); |
| 2882 context()->Plug(rax); | 3070 context()->Plug(rax); |
| 2883 } | 3071 } |
| 2884 | 3072 |
| 2885 | 3073 |
| 2886 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { | 3074 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { |
| 2887 ASSERT_EQ(2, args->length()); | 3075 ASSERT_EQ(2, args->length()); |
| 2888 | 3076 |
| 2889 ASSERT_NE(NULL, args->at(0)->AsLiteral()); | 3077 ASSERT_NE(NULL, args->at(0)->AsLiteral()); |
| 2890 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); | 3078 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); |
| 2891 | 3079 |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2994 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3182 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 2995 __ j(zero, if_true); | 3183 __ j(zero, if_true); |
| 2996 __ jmp(if_false); | 3184 __ jmp(if_false); |
| 2997 | 3185 |
| 2998 context()->Plug(if_true, if_false); | 3186 context()->Plug(if_true, if_false); |
| 2999 } | 3187 } |
| 3000 | 3188 |
| 3001 | 3189 |
| 3002 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { | 3190 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { |
| 3003 ASSERT(args->length() == 1); | 3191 ASSERT(args->length() == 1); |
| 3192 VisitForAccumulatorValue(args->at(0)); |
| 3004 | 3193 |
| 3005 VisitForAccumulatorValue(args->at(0)); | 3194 if (FLAG_debug_code) { |
| 3195 __ AbortIfNotString(rax); |
| 3196 } |
| 3006 | 3197 |
| 3007 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset)); | 3198 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset)); |
| 3008 ASSERT(String::kHashShift >= kSmiTagSize); | 3199 ASSERT(String::kHashShift >= kSmiTagSize); |
| 3009 __ IndexFromHash(rax, rax); | 3200 __ IndexFromHash(rax, rax); |
| 3010 | 3201 |
| 3011 context()->Plug(rax); | 3202 context()->Plug(rax); |
| 3012 } | 3203 } |
| 3013 | 3204 |
| 3014 | 3205 |
| 3015 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { | 3206 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3069 context()->Plug(false); | 3260 context()->Plug(false); |
| 3070 } else { | 3261 } else { |
| 3071 VisitForStackValue(prop->obj()); | 3262 VisitForStackValue(prop->obj()); |
| 3072 VisitForStackValue(prop->key()); | 3263 VisitForStackValue(prop->key()); |
| 3073 __ Push(Smi::FromInt(strict_mode_flag())); | 3264 __ Push(Smi::FromInt(strict_mode_flag())); |
| 3074 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3265 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3075 context()->Plug(rax); | 3266 context()->Plug(rax); |
| 3076 } | 3267 } |
| 3077 } else if (var != NULL) { | 3268 } else if (var != NULL) { |
| 3078 // Delete of an unqualified identifier is disallowed in strict mode | 3269 // Delete of an unqualified identifier is disallowed in strict mode |
| 3079 // so this code can only be reached in non-strict mode. | 3270 // but "delete this" is. |
| 3080 ASSERT(strict_mode_flag() == kNonStrictMode); | 3271 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this()); |
| 3081 if (var->is_global()) { | 3272 if (var->is_global()) { |
| 3082 __ push(GlobalObjectOperand()); | 3273 __ push(GlobalObjectOperand()); |
| 3083 __ Push(var->name()); | 3274 __ Push(var->name()); |
| 3084 __ Push(Smi::FromInt(kNonStrictMode)); | 3275 __ Push(Smi::FromInt(kNonStrictMode)); |
| 3085 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3276 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3086 context()->Plug(rax); | 3277 context()->Plug(rax); |
| 3087 } else if (var->AsSlot() != NULL && | 3278 } else if (var->AsSlot() != NULL && |
| 3088 var->AsSlot()->type() != Slot::LOOKUP) { | 3279 var->AsSlot()->type() != Slot::LOOKUP) { |
| 3089 // Result of deleting non-global, non-dynamic variables is false. | 3280 // Result of deleting non-global, non-dynamic variables is false. |
| 3090 // The subexpression does not have side effects. | 3281 // The subexpression does not have side effects. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 3108 | 3299 |
| 3109 case Token::VOID: { | 3300 case Token::VOID: { |
| 3110 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 3301 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
| 3111 VisitForEffect(expr->expression()); | 3302 VisitForEffect(expr->expression()); |
| 3112 context()->Plug(Heap::kUndefinedValueRootIndex); | 3303 context()->Plug(Heap::kUndefinedValueRootIndex); |
| 3113 break; | 3304 break; |
| 3114 } | 3305 } |
| 3115 | 3306 |
| 3116 case Token::NOT: { | 3307 case Token::NOT: { |
| 3117 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); | 3308 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); |
| 3118 Label materialize_true, materialize_false; | 3309 if (context()->IsEffect()) { |
| 3119 Label* if_true = NULL; | 3310 // Unary NOT has no side effects so it's only necessary to visit the |
| 3120 Label* if_false = NULL; | 3311 // subexpression. Match the optimizing compiler by not branching. |
| 3121 Label* fall_through = NULL; | 3312 VisitForEffect(expr->expression()); |
| 3122 // Notice that the labels are swapped. | 3313 } else { |
| 3123 context()->PrepareTest(&materialize_true, &materialize_false, | 3314 Label materialize_true, materialize_false; |
| 3124 &if_false, &if_true, &fall_through); | 3315 Label* if_true = NULL; |
| 3125 if (context()->IsTest()) ForwardBailoutToChild(expr); | 3316 Label* if_false = NULL; |
| 3126 VisitForControl(expr->expression(), if_true, if_false, fall_through); | 3317 Label* fall_through = NULL; |
| 3127 context()->Plug(if_false, if_true); // Labels swapped. | 3318 // Notice that the labels are swapped. |
| 3319 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3320 &if_false, &if_true, &fall_through); |
| 3321 if (context()->IsTest()) ForwardBailoutToChild(expr); |
| 3322 VisitForControl(expr->expression(), if_true, if_false, fall_through); |
| 3323 context()->Plug(if_false, if_true); // Labels swapped. |
| 3324 } |
| 3128 break; | 3325 break; |
| 3129 } | 3326 } |
| 3130 | 3327 |
| 3131 case Token::TYPEOF: { | 3328 case Token::TYPEOF: { |
| 3132 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); | 3329 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); |
| 3133 { StackValueContext context(this); | 3330 { StackValueContext context(this); |
| 3134 VisitForTypeofValue(expr->expression()); | 3331 VisitForTypeofValue(expr->expression()); |
| 3135 } | 3332 } |
| 3136 __ CallRuntime(Runtime::kTypeof, 1); | 3333 __ CallRuntime(Runtime::kTypeof, 1); |
| 3137 context()->Plug(rax); | 3334 context()->Plug(rax); |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3343 // Perform the assignment as if via '='. | 3540 // Perform the assignment as if via '='. |
| 3344 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 3541 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 3345 Token::ASSIGN); | 3542 Token::ASSIGN); |
| 3346 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3543 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3347 context()->Plug(rax); | 3544 context()->Plug(rax); |
| 3348 } | 3545 } |
| 3349 break; | 3546 break; |
| 3350 case NAMED_PROPERTY: { | 3547 case NAMED_PROPERTY: { |
| 3351 __ Move(rcx, prop->key()->AsLiteral()->handle()); | 3548 __ Move(rcx, prop->key()->AsLiteral()->handle()); |
| 3352 __ pop(rdx); | 3549 __ pop(rdx); |
| 3353 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 3550 Handle<Code> ic(Builtins::builtin( |
| 3551 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict |
| 3552 : Builtins::StoreIC_Initialize)); |
| 3354 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3553 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3355 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3554 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3356 if (expr->is_postfix()) { | 3555 if (expr->is_postfix()) { |
| 3357 if (!context()->IsEffect()) { | 3556 if (!context()->IsEffect()) { |
| 3358 context()->PlugTOS(); | 3557 context()->PlugTOS(); |
| 3359 } | 3558 } |
| 3360 } else { | 3559 } else { |
| 3361 context()->Plug(rax); | 3560 context()->Plug(rax); |
| 3362 } | 3561 } |
| 3363 break; | 3562 break; |
| 3364 } | 3563 } |
| 3365 case KEYED_PROPERTY: { | 3564 case KEYED_PROPERTY: { |
| 3366 __ pop(rcx); | 3565 __ pop(rcx); |
| 3367 __ pop(rdx); | 3566 __ pop(rdx); |
| 3368 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 3567 Handle<Code> ic(Builtins::builtin( |
| 3568 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict |
| 3569 : Builtins::KeyedStoreIC_Initialize)); |
| 3369 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 3570 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 3370 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 3571 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 3371 if (expr->is_postfix()) { | 3572 if (expr->is_postfix()) { |
| 3372 if (!context()->IsEffect()) { | 3573 if (!context()->IsEffect()) { |
| 3373 context()->PlugTOS(); | 3574 context()->PlugTOS(); |
| 3374 } | 3575 } |
| 3375 } else { | 3576 } else { |
| 3376 context()->Plug(rax); | 3577 context()->Plug(rax); |
| 3377 } | 3578 } |
| 3378 break; | 3579 break; |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3437 UnaryOperation* left_unary = left->AsUnaryOperation(); | 3638 UnaryOperation* left_unary = left->AsUnaryOperation(); |
| 3438 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; | 3639 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; |
| 3439 Handle<String> check = Handle<String>::cast(right_literal_value); | 3640 Handle<String> check = Handle<String>::cast(right_literal_value); |
| 3440 | 3641 |
| 3441 { AccumulatorValueContext context(this); | 3642 { AccumulatorValueContext context(this); |
| 3442 VisitForTypeofValue(left_unary->expression()); | 3643 VisitForTypeofValue(left_unary->expression()); |
| 3443 } | 3644 } |
| 3444 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); | 3645 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); |
| 3445 | 3646 |
| 3446 if (check->Equals(Heap::number_symbol())) { | 3647 if (check->Equals(Heap::number_symbol())) { |
| 3447 Condition is_smi = masm_->CheckSmi(rax); | 3648 __ JumpIfSmi(rax, if_true); |
| 3448 __ j(is_smi, if_true); | |
| 3449 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); | 3649 __ movq(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
| 3450 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); | 3650 __ CompareRoot(rax, Heap::kHeapNumberMapRootIndex); |
| 3451 Split(equal, if_true, if_false, fall_through); | 3651 Split(equal, if_true, if_false, fall_through); |
| 3452 } else if (check->Equals(Heap::string_symbol())) { | 3652 } else if (check->Equals(Heap::string_symbol())) { |
| 3453 Condition is_smi = masm_->CheckSmi(rax); | 3653 __ JumpIfSmi(rax, if_false); |
| 3454 __ j(is_smi, if_false); | |
| 3455 // Check for undetectable objects => false. | 3654 // Check for undetectable objects => false. |
| 3456 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 3655 __ CmpObjectType(rax, FIRST_NONSTRING_TYPE, rdx); |
| 3656 __ j(above_equal, if_false); |
| 3457 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), | 3657 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
| 3458 Immediate(1 << Map::kIsUndetectable)); | 3658 Immediate(1 << Map::kIsUndetectable)); |
| 3459 __ j(not_zero, if_false); | 3659 Split(zero, if_true, if_false, fall_through); |
| 3460 __ CmpInstanceType(rdx, FIRST_NONSTRING_TYPE); | |
| 3461 Split(below, if_true, if_false, fall_through); | |
| 3462 } else if (check->Equals(Heap::boolean_symbol())) { | 3660 } else if (check->Equals(Heap::boolean_symbol())) { |
| 3463 __ CompareRoot(rax, Heap::kTrueValueRootIndex); | 3661 __ CompareRoot(rax, Heap::kTrueValueRootIndex); |
| 3464 __ j(equal, if_true); | 3662 __ j(equal, if_true); |
| 3465 __ CompareRoot(rax, Heap::kFalseValueRootIndex); | 3663 __ CompareRoot(rax, Heap::kFalseValueRootIndex); |
| 3466 Split(equal, if_true, if_false, fall_through); | 3664 Split(equal, if_true, if_false, fall_through); |
| 3467 } else if (check->Equals(Heap::undefined_symbol())) { | 3665 } else if (check->Equals(Heap::undefined_symbol())) { |
| 3468 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); | 3666 __ CompareRoot(rax, Heap::kUndefinedValueRootIndex); |
| 3469 __ j(equal, if_true); | 3667 __ j(equal, if_true); |
| 3470 Condition is_smi = masm_->CheckSmi(rax); | 3668 __ JumpIfSmi(rax, if_false); |
| 3471 __ j(is_smi, if_false); | |
| 3472 // Check for undetectable objects => true. | 3669 // Check for undetectable objects => true. |
| 3473 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); | 3670 __ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset)); |
| 3474 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), | 3671 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
| 3475 Immediate(1 << Map::kIsUndetectable)); | 3672 Immediate(1 << Map::kIsUndetectable)); |
| 3476 Split(not_zero, if_true, if_false, fall_through); | 3673 Split(not_zero, if_true, if_false, fall_through); |
| 3477 } else if (check->Equals(Heap::function_symbol())) { | 3674 } else if (check->Equals(Heap::function_symbol())) { |
| 3478 Condition is_smi = masm_->CheckSmi(rax); | 3675 __ JumpIfSmi(rax, if_false); |
| 3479 __ j(is_smi, if_false); | 3676 __ CmpObjectType(rax, FIRST_FUNCTION_CLASS_TYPE, rdx); |
| 3480 __ CmpObjectType(rax, JS_FUNCTION_TYPE, rdx); | 3677 Split(above_equal, if_true, if_false, fall_through); |
| 3481 __ j(equal, if_true); | |
| 3482 // Regular expressions => 'function' (they are callable). | |
| 3483 __ CmpInstanceType(rdx, JS_REGEXP_TYPE); | |
| 3484 Split(equal, if_true, if_false, fall_through); | |
| 3485 } else if (check->Equals(Heap::object_symbol())) { | 3678 } else if (check->Equals(Heap::object_symbol())) { |
| 3486 Condition is_smi = masm_->CheckSmi(rax); | 3679 __ JumpIfSmi(rax, if_false); |
| 3487 __ j(is_smi, if_false); | |
| 3488 __ CompareRoot(rax, Heap::kNullValueRootIndex); | 3680 __ CompareRoot(rax, Heap::kNullValueRootIndex); |
| 3489 __ j(equal, if_true); | 3681 __ j(equal, if_true); |
| 3490 // Regular expressions => 'function', not 'object'. | 3682 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rdx); |
| 3491 __ CmpObjectType(rax, JS_REGEXP_TYPE, rdx); | 3683 __ j(below, if_false); |
| 3492 __ j(equal, if_false); | 3684 __ CmpInstanceType(rdx, FIRST_FUNCTION_CLASS_TYPE); |
| 3685 __ j(above_equal, if_false); |
| 3493 // Check for undetectable objects => false. | 3686 // Check for undetectable objects => false. |
| 3494 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), | 3687 __ testb(FieldOperand(rdx, Map::kBitFieldOffset), |
| 3495 Immediate(1 << Map::kIsUndetectable)); | 3688 Immediate(1 << Map::kIsUndetectable)); |
| 3496 __ j(not_zero, if_false); | 3689 Split(zero, if_true, if_false, fall_through); |
| 3497 // Check for JS objects => true. | |
| 3498 __ CmpInstanceType(rdx, FIRST_JS_OBJECT_TYPE); | |
| 3499 __ j(below, if_false); | |
| 3500 __ CmpInstanceType(rdx, LAST_JS_OBJECT_TYPE); | |
| 3501 Split(below_equal, if_true, if_false, fall_through); | |
| 3502 } else { | 3690 } else { |
| 3503 if (if_false != fall_through) __ jmp(if_false); | 3691 if (if_false != fall_through) __ jmp(if_false); |
| 3504 } | 3692 } |
| 3505 | 3693 |
| 3506 return true; | 3694 return true; |
| 3507 } | 3695 } |
| 3508 | 3696 |
| 3509 | 3697 |
| 3510 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { | 3698 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
| 3511 Comment cmnt(masm_, "[ CompareOperation"); | 3699 Comment cmnt(masm_, "[ CompareOperation"); |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3703 __ nop(); // Signals no inlined code. | 3891 __ nop(); // Signals no inlined code. |
| 3704 break; | 3892 break; |
| 3705 default: | 3893 default: |
| 3706 // Do nothing. | 3894 // Do nothing. |
| 3707 break; | 3895 break; |
| 3708 } | 3896 } |
| 3709 } | 3897 } |
| 3710 | 3898 |
| 3711 | 3899 |
| 3712 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { | 3900 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { |
| 3901 switch (ic->kind()) { |
| 3902 case Code::LOAD_IC: |
| 3903 __ IncrementCounter(&Counters::named_load_full, 1); |
| 3904 break; |
| 3905 case Code::KEYED_LOAD_IC: |
| 3906 __ IncrementCounter(&Counters::keyed_load_full, 1); |
| 3907 break; |
| 3908 case Code::STORE_IC: |
| 3909 __ IncrementCounter(&Counters::named_store_full, 1); |
| 3910 break; |
| 3911 case Code::KEYED_STORE_IC: |
| 3912 __ IncrementCounter(&Counters::keyed_store_full, 1); |
| 3913 default: |
| 3914 break; |
| 3915 } |
| 3916 |
| 3713 __ call(ic, RelocInfo::CODE_TARGET); | 3917 __ call(ic, RelocInfo::CODE_TARGET); |
| 3714 if (patch_site != NULL && patch_site->is_bound()) { | 3918 if (patch_site != NULL && patch_site->is_bound()) { |
| 3715 patch_site->EmitPatchInfo(); | 3919 patch_site->EmitPatchInfo(); |
| 3716 } else { | 3920 } else { |
| 3717 __ nop(); // Signals no inlined code. | 3921 __ nop(); // Signals no inlined code. |
| 3718 } | 3922 } |
| 3719 } | 3923 } |
| 3720 | 3924 |
| 3721 | 3925 |
| 3722 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { | 3926 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3763 __ ret(0); | 3967 __ ret(0); |
| 3764 } | 3968 } |
| 3765 | 3969 |
| 3766 | 3970 |
| 3767 #undef __ | 3971 #undef __ |
| 3768 | 3972 |
| 3769 | 3973 |
| 3770 } } // namespace v8::internal | 3974 } } // namespace v8::internal |
| 3771 | 3975 |
| 3772 #endif // V8_TARGET_ARCH_X64 | 3976 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |