Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(37)

Side by Side Diff: src/arm/full-codegen-arm.cc

Issue 6697023: Merge 6800:7180 from the bleeding edge branch to the experimental/gc branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/arm/disasm-arm.cc ('k') | src/arm/ic-arm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 Operand(StandardFrameConstants::kCallerSPOffset + offset)); 208 Operand(StandardFrameConstants::kCallerSPOffset + offset));
209 __ mov(r1, Operand(Smi::FromInt(scope()->num_parameters()))); 209 __ mov(r1, Operand(Smi::FromInt(scope()->num_parameters())));
210 __ Push(r3, r2, r1); 210 __ Push(r3, r2, r1);
211 211
212 // Arguments to ArgumentsAccessStub: 212 // Arguments to ArgumentsAccessStub:
213 // function, receiver address, parameter count. 213 // function, receiver address, parameter count.
214 // The stub will rewrite receiever and parameter count if the previous 214 // The stub will rewrite receiever and parameter count if the previous
215 // stack frame was an arguments adapter frame. 215 // stack frame was an arguments adapter frame.
216 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); 216 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
217 __ CallStub(&stub); 217 __ CallStub(&stub);
218 // Duplicate the value; move-to-slot operation might clobber registers. 218
219 __ mov(r3, r0); 219 Variable* arguments_shadow = scope()->arguments_shadow();
220 if (arguments_shadow != NULL) {
221 // Duplicate the value; move-to-slot operation might clobber registers.
222 __ mov(r3, r0);
223 Move(arguments_shadow->AsSlot(), r3, r1, r2);
224 }
220 Move(arguments->AsSlot(), r0, r1, r2); 225 Move(arguments->AsSlot(), r0, r1, r2);
221 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot();
222 Move(dot_arguments_slot, r3, r1, r2);
223 }
224
225 { Comment cmnt(masm_, "[ Declarations");
226 // For named function expressions, declare the function name as a
227 // constant.
228 if (scope()->is_function_scope() && scope()->function() != NULL) {
229 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
230 }
231 // Visit all the explicit declarations unless there is an illegal
232 // redeclaration.
233 if (scope()->HasIllegalRedeclaration()) {
234 scope()->VisitIllegalRedeclaration(this);
235 } else {
236 VisitDeclarations(scope()->declarations());
237 }
238 } 226 }
239 227
240 if (FLAG_trace) { 228 if (FLAG_trace) {
241 __ CallRuntime(Runtime::kTraceEnter, 0); 229 __ CallRuntime(Runtime::kTraceEnter, 0);
242 } 230 }
243 231
244 // Check the stack for overflow or break request. 232 // Visit the declarations and body unless there is an illegal
245 { Comment cmnt(masm_, "[ Stack check"); 233 // redeclaration.
246 PrepareForBailout(info->function(), NO_REGISTERS); 234 if (scope()->HasIllegalRedeclaration()) {
247 Label ok; 235 Comment cmnt(masm_, "[ Declarations");
248 __ LoadRoot(ip, Heap::kStackLimitRootIndex); 236 scope()->VisitIllegalRedeclaration(this);
249 __ cmp(sp, Operand(ip)); 237
250 __ b(hs, &ok); 238 } else {
251 StackCheckStub stub; 239 { Comment cmnt(masm_, "[ Declarations");
252 __ CallStub(&stub); 240 // For named function expressions, declare the function name as a
253 __ bind(&ok); 241 // constant.
242 if (scope()->is_function_scope() && scope()->function() != NULL) {
243 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
244 }
245 VisitDeclarations(scope()->declarations());
246 }
247
248 { Comment cmnt(masm_, "[ Stack check");
249 PrepareForBailout(info->function(), NO_REGISTERS);
250 Label ok;
251 __ LoadRoot(ip, Heap::kStackLimitRootIndex);
252 __ cmp(sp, Operand(ip));
253 __ b(hs, &ok);
254 StackCheckStub stub;
255 __ CallStub(&stub);
256 __ bind(&ok);
257 }
258
259 { Comment cmnt(masm_, "[ Body");
260 ASSERT(loop_depth() == 0);
261 VisitStatements(function()->body());
262 ASSERT(loop_depth() == 0);
263 }
254 } 264 }
255 265
256 { Comment cmnt(masm_, "[ Body"); 266 // Always emit a 'return undefined' in case control fell off the end of
257 ASSERT(loop_depth() == 0); 267 // the body.
258 VisitStatements(function()->body());
259 ASSERT(loop_depth() == 0);
260 }
261
262 { Comment cmnt(masm_, "[ return <undefined>;"); 268 { Comment cmnt(masm_, "[ return <undefined>;");
263 // Emit a 'return undefined' in case control fell off the end of the
264 // body.
265 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); 269 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
266 } 270 }
267 EmitReturnSequence(); 271 EmitReturnSequence();
268 272
269 // Force emit the constant pool, so it doesn't get emitted in the middle 273 // Force emit the constant pool, so it doesn't get emitted in the middle
270 // of the stack check table. 274 // of the stack check table.
271 masm()->CheckConstPool(true, false); 275 masm()->CheckConstPool(true, false);
272 } 276 }
273 277
274 278
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 #ifdef DEBUG 338 #ifdef DEBUG
335 // Check that the size of the code used for returning is large enough 339 // Check that the size of the code used for returning is large enough
336 // for the debugger's requirements. 340 // for the debugger's requirements.
337 ASSERT(Assembler::kJSReturnSequenceInstructions <= 341 ASSERT(Assembler::kJSReturnSequenceInstructions <=
338 masm_->InstructionsGeneratedSince(&check_exit_codesize)); 342 masm_->InstructionsGeneratedSince(&check_exit_codesize));
339 #endif 343 #endif
340 } 344 }
341 } 345 }
342 346
343 347
344 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
345 Token::Value op, Expression* left, Expression* right) {
346 ASSERT(ShouldInlineSmiCase(op));
347 return kNoConstants;
348 }
349
350
351 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { 348 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
352 } 349 }
353 350
354 351
355 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { 352 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
356 codegen()->Move(result_register(), slot); 353 codegen()->Move(result_register(), slot);
357 } 354 }
358 355
359 356
360 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { 357 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 if (true_label_ != fall_through_) __ b(true_label_); 556 if (true_label_ != fall_through_) __ b(true_label_);
560 } else { 557 } else {
561 if (false_label_ != fall_through_) __ b(false_label_); 558 if (false_label_ != fall_through_) __ b(false_label_);
562 } 559 }
563 } 560 }
564 561
565 562
566 void FullCodeGenerator::DoTest(Label* if_true, 563 void FullCodeGenerator::DoTest(Label* if_true,
567 Label* if_false, 564 Label* if_false,
568 Label* fall_through) { 565 Label* fall_through) {
569 // Call the runtime to find the boolean value of the source and then 566 if (CpuFeatures::IsSupported(VFP3)) {
570 // translate it into control flow to the pair of labels. 567 CpuFeatures::Scope scope(VFP3);
571 __ push(result_register()); 568 // Emit the inlined tests assumed by the stub.
572 __ CallRuntime(Runtime::kToBool, 1); 569 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
573 __ LoadRoot(ip, Heap::kTrueValueRootIndex); 570 __ cmp(result_register(), ip);
574 __ cmp(r0, ip); 571 __ b(eq, if_false);
575 Split(eq, if_true, if_false, fall_through); 572 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
573 __ cmp(result_register(), ip);
574 __ b(eq, if_true);
575 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
576 __ cmp(result_register(), ip);
577 __ b(eq, if_false);
578 STATIC_ASSERT(kSmiTag == 0);
579 __ tst(result_register(), result_register());
580 __ b(eq, if_false);
581 __ JumpIfSmi(result_register(), if_true);
582
583 // Call the ToBoolean stub for all other cases.
584 ToBooleanStub stub(result_register());
585 __ CallStub(&stub);
586 __ tst(result_register(), result_register());
587 } else {
588 // Call the runtime to find the boolean value of the source and then
589 // translate it into control flow to the pair of labels.
590 __ push(result_register());
591 __ CallRuntime(Runtime::kToBool, 1);
592 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
593 __ cmp(r0, ip);
594 }
595
596 // The stub returns nonzero for true.
597 Split(ne, if_true, if_false, fall_through);
576 } 598 }
577 599
578 600
579 void FullCodeGenerator::Split(Condition cond, 601 void FullCodeGenerator::Split(Condition cond,
580 Label* if_true, 602 Label* if_true,
581 Label* if_false, 603 Label* if_false,
582 Label* fall_through) { 604 Label* fall_through) {
583 if (if_false == fall_through) { 605 if (if_false == fall_through) {
584 __ b(cond, if_true); 606 __ b(cond, if_true);
585 } else if (if_true == fall_through) { 607 } else if (if_true == fall_through) {
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
683 } else if (function != NULL) { 705 } else if (function != NULL) {
684 VisitForAccumulatorValue(function); 706 VisitForAccumulatorValue(function);
685 __ str(result_register(), MemOperand(fp, SlotOffset(slot))); 707 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
686 } 708 }
687 break; 709 break;
688 710
689 case Slot::CONTEXT: 711 case Slot::CONTEXT:
690 // We bypass the general EmitSlotSearch because we know more about 712 // We bypass the general EmitSlotSearch because we know more about
691 // this specific context. 713 // this specific context.
692 714
693 // The variable in the decl always resides in the current context. 715 // The variable in the decl always resides in the current function
716 // context.
694 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); 717 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
695 if (FLAG_debug_code) { 718 if (FLAG_debug_code) {
696 // Check if we have the correct context pointer. 719 // Check that we're not inside a 'with'.
697 __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX)); 720 __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX));
698 __ cmp(r1, cp); 721 __ cmp(r1, cp);
699 __ Check(eq, "Unexpected declaration in current context."); 722 __ Check(eq, "Unexpected declaration in current context.");
700 } 723 }
701 if (mode == Variable::CONST) { 724 if (mode == Variable::CONST) {
702 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); 725 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
703 __ str(ip, ContextOperand(cp, slot->index())); 726 __ str(ip, ContextOperand(cp, slot->index()));
704 // No write barrier since the_hole_value is in old space. 727 // No write barrier since the_hole_value is in old space.
705 } else if (function != NULL) { 728 } else if (function != NULL) {
706 VisitForAccumulatorValue(function); 729 VisitForAccumulatorValue(function);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 VisitForAccumulatorValue(function); 781 VisitForAccumulatorValue(function);
759 __ pop(r2); 782 __ pop(r2);
760 } else { 783 } else {
761 __ mov(r2, r0); 784 __ mov(r2, r0);
762 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); 785 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
763 } 786 }
764 ASSERT(prop->key()->AsLiteral() != NULL && 787 ASSERT(prop->key()->AsLiteral() != NULL &&
765 prop->key()->AsLiteral()->handle()->IsSmi()); 788 prop->key()->AsLiteral()->handle()->IsSmi());
766 __ mov(r1, Operand(prop->key()->AsLiteral()->handle())); 789 __ mov(r1, Operand(prop->key()->AsLiteral()->handle()));
767 790
768 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 791 Handle<Code> ic(Builtins::builtin(
792 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict
793 : Builtins::KeyedStoreIC_Initialize));
769 EmitCallIC(ic, RelocInfo::CODE_TARGET); 794 EmitCallIC(ic, RelocInfo::CODE_TARGET);
770 // Value in r0 is ignored (declarations are statements). 795 // Value in r0 is ignored (declarations are statements).
771 } 796 }
772 } 797 }
773 } 798 }
774 799
775 800
776 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { 801 void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
777 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); 802 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
778 } 803 }
779 804
780 805
781 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 806 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
782 // Call the runtime to declare the globals. 807 // Call the runtime to declare the globals.
783 // The context is the first argument. 808 // The context is the first argument.
784 __ mov(r1, Operand(pairs)); 809 __ mov(r2, Operand(pairs));
785 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); 810 __ mov(r1, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
786 __ Push(cp, r1, r0); 811 __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
787 __ CallRuntime(Runtime::kDeclareGlobals, 3); 812 __ Push(cp, r2, r1, r0);
813 __ CallRuntime(Runtime::kDeclareGlobals, 4);
788 // Return value is ignored. 814 // Return value is ignored.
789 } 815 }
790 816
791 817
792 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { 818 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
793 Comment cmnt(masm_, "[ SwitchStatement"); 819 Comment cmnt(masm_, "[ SwitchStatement");
794 Breakable nested_statement(this, stmt); 820 Breakable nested_statement(this, stmt);
795 SetStatementPosition(stmt); 821 SetStatementPosition(stmt);
822
796 // Keep the switch value on the stack until a case matches. 823 // Keep the switch value on the stack until a case matches.
797 VisitForStackValue(stmt->tag()); 824 VisitForStackValue(stmt->tag());
798
799 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); 825 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
800 826
801 ZoneList<CaseClause*>* clauses = stmt->cases(); 827 ZoneList<CaseClause*>* clauses = stmt->cases();
802 CaseClause* default_clause = NULL; // Can occur anywhere in the list. 828 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
803 829
804 Label next_test; // Recycled for each test. 830 Label next_test; // Recycled for each test.
805 // Compile all the tests with branches to their bodies. 831 // Compile all the tests with branches to their bodies.
806 for (int i = 0; i < clauses->length(); i++) { 832 for (int i = 0; i < clauses->length(); i++) {
807 CaseClause* clause = clauses->at(i); 833 CaseClause* clause = clauses->at(i);
808 clause->body_target()->entry_label()->Unuse(); 834 clause->body_target()->entry_label()->Unuse();
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
854 __ b(nested_statement.break_target()); 880 __ b(nested_statement.break_target());
855 } else { 881 } else {
856 __ b(default_clause->body_target()->entry_label()); 882 __ b(default_clause->body_target()->entry_label());
857 } 883 }
858 884
859 // Compile all the case bodies. 885 // Compile all the case bodies.
860 for (int i = 0; i < clauses->length(); i++) { 886 for (int i = 0; i < clauses->length(); i++) {
861 Comment cmnt(masm_, "[ Case body"); 887 Comment cmnt(masm_, "[ Case body");
862 CaseClause* clause = clauses->at(i); 888 CaseClause* clause = clauses->at(i);
863 __ bind(clause->body_target()->entry_label()); 889 __ bind(clause->body_target()->entry_label());
890 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
864 VisitStatements(clause->statements()); 891 VisitStatements(clause->statements());
865 } 892 }
866 893
867 __ bind(nested_statement.break_target()); 894 __ bind(nested_statement.break_target());
868 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); 895 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
869 } 896 }
870 897
871 898
872 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { 899 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
873 Comment cmnt(masm_, "[ ForInStatement"); 900 Comment cmnt(masm_, "[ ForInStatement");
874 SetStatementPosition(stmt); 901 SetStatementPosition(stmt);
875 902
876 Label loop, exit; 903 Label loop, exit;
877 ForIn loop_statement(this, stmt); 904 ForIn loop_statement(this, stmt);
878 increment_loop_depth(); 905 increment_loop_depth();
879 906
880 // Get the object to enumerate over. Both SpiderMonkey and JSC 907 // Get the object to enumerate over. Both SpiderMonkey and JSC
881 // ignore null and undefined in contrast to the specification; see 908 // ignore null and undefined in contrast to the specification; see
882 // ECMA-262 section 12.6.4. 909 // ECMA-262 section 12.6.4.
883 VisitForAccumulatorValue(stmt->enumerable()); 910 VisitForAccumulatorValue(stmt->enumerable());
884 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 911 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
885 __ cmp(r0, ip); 912 __ cmp(r0, ip);
886 __ b(eq, &exit); 913 __ b(eq, &exit);
887 __ LoadRoot(ip, Heap::kNullValueRootIndex); 914 Register null_value = r5;
888 __ cmp(r0, ip); 915 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
916 __ cmp(r0, null_value);
889 __ b(eq, &exit); 917 __ b(eq, &exit);
890 918
891 // Convert the object to a JS object. 919 // Convert the object to a JS object.
892 Label convert, done_convert; 920 Label convert, done_convert;
893 __ JumpIfSmi(r0, &convert); 921 __ JumpIfSmi(r0, &convert);
894 __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE); 922 __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
895 __ b(hs, &done_convert); 923 __ b(hs, &done_convert);
896 __ bind(&convert); 924 __ bind(&convert);
897 __ push(r0); 925 __ push(r0);
898 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); 926 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
899 __ bind(&done_convert); 927 __ bind(&done_convert);
900 __ push(r0); 928 __ push(r0);
901 929
902 // BUG(867): Check cache validity in generated code. This is a fast 930 // Check cache validity in generated code. This is a fast case for
903 // case for the JSObject::IsSimpleEnum cache validity checks. If we 931 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
904 // cannot guarantee cache validity, call the runtime system to check 932 // guarantee cache validity, call the runtime system to check cache
905 // cache validity or get the property names in a fixed array. 933 // validity or get the property names in a fixed array.
934 Label next, call_runtime;
935 // Preload a couple of values used in the loop.
936 Register empty_fixed_array_value = r6;
937 __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
938 Register empty_descriptor_array_value = r7;
939 __ LoadRoot(empty_descriptor_array_value,
940 Heap::kEmptyDescriptorArrayRootIndex);
941 __ mov(r1, r0);
942 __ bind(&next);
943
944 // Check that there are no elements. Register r1 contains the
945 // current JS object we've reached through the prototype chain.
946 __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
947 __ cmp(r2, empty_fixed_array_value);
948 __ b(ne, &call_runtime);
949
950 // Check that instance descriptors are not empty so that we can
951 // check for an enum cache. Leave the map in r2 for the subsequent
952 // prototype load.
953 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
954 __ ldr(r3, FieldMemOperand(r2, Map::kInstanceDescriptorsOffset));
955 __ cmp(r3, empty_descriptor_array_value);
956 __ b(eq, &call_runtime);
957
958 // Check that there is an enum cache in the non-empty instance
959 // descriptors (r3). This is the case if the next enumeration
960 // index field does not contain a smi.
961 __ ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumerationIndexOffset));
962 __ JumpIfSmi(r3, &call_runtime);
963
964 // For all objects but the receiver, check that the cache is empty.
965 Label check_prototype;
966 __ cmp(r1, r0);
967 __ b(eq, &check_prototype);
968 __ ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumCacheBridgeCacheOffset));
969 __ cmp(r3, empty_fixed_array_value);
970 __ b(ne, &call_runtime);
971
972 // Load the prototype from the map and loop if non-null.
973 __ bind(&check_prototype);
974 __ ldr(r1, FieldMemOperand(r2, Map::kPrototypeOffset));
975 __ cmp(r1, null_value);
976 __ b(ne, &next);
977
978 // The enum cache is valid. Load the map of the object being
979 // iterated over and use the cache for the iteration.
980 Label use_cache;
981 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
982 __ b(&use_cache);
906 983
907 // Get the set of properties to enumerate. 984 // Get the set of properties to enumerate.
985 __ bind(&call_runtime);
908 __ push(r0); // Duplicate the enumerable object on the stack. 986 __ push(r0); // Duplicate the enumerable object on the stack.
909 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); 987 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
910 988
911 // If we got a map from the runtime call, we can do a fast 989 // If we got a map from the runtime call, we can do a fast
912 // modification check. Otherwise, we got a fixed array, and we have 990 // modification check. Otherwise, we got a fixed array, and we have
913 // to do a slow check. 991 // to do a slow check.
914 Label fixed_array; 992 Label fixed_array;
915 __ mov(r2, r0); 993 __ mov(r2, r0);
916 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); 994 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
917 __ LoadRoot(ip, Heap::kMetaMapRootIndex); 995 __ LoadRoot(ip, Heap::kMetaMapRootIndex);
918 __ cmp(r1, ip); 996 __ cmp(r1, ip);
919 __ b(ne, &fixed_array); 997 __ b(ne, &fixed_array);
920 998
921 // We got a map in register r0. Get the enumeration cache from it. 999 // We got a map in register r0. Get the enumeration cache from it.
1000 __ bind(&use_cache);
922 __ ldr(r1, FieldMemOperand(r0, Map::kInstanceDescriptorsOffset)); 1001 __ ldr(r1, FieldMemOperand(r0, Map::kInstanceDescriptorsOffset));
923 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset)); 1002 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
924 __ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset)); 1003 __ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
925 1004
926 // Setup the four remaining stack slots. 1005 // Setup the four remaining stack slots.
927 __ push(r0); // Map. 1006 __ push(r0); // Map.
928 __ ldr(r1, FieldMemOperand(r2, FixedArray::kLengthOffset)); 1007 __ ldr(r1, FieldMemOperand(r2, FixedArray::kLengthOffset));
929 __ mov(r0, Operand(Smi::FromInt(0))); 1008 __ mov(r0, Operand(Smi::FromInt(0)));
930 // Push enumeration cache, enumeration cache length (as smi) and zero. 1009 // Push enumeration cache, enumeration cache length (as smi) and zero.
931 __ Push(r2, r1, r0); 1010 __ Push(r2, r1, r0);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
1000 1079
1001 // Exit and decrement the loop depth. 1080 // Exit and decrement the loop depth.
1002 __ bind(&exit); 1081 __ bind(&exit);
1003 decrement_loop_depth(); 1082 decrement_loop_depth();
1004 } 1083 }
1005 1084
1006 1085
1007 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, 1086 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1008 bool pretenure) { 1087 bool pretenure) {
1009 // Use the fast case closure allocation code that allocates in new 1088 // Use the fast case closure allocation code that allocates in new
1010 // space for nested functions that don't need literals cloning. 1089 // space for nested functions that don't need literals cloning. If
1011 if (scope()->is_function_scope() && 1090 // we're running with the --always-opt or the --prepare-always-opt
1091 // flag, we need to use the runtime function so that the new function
1092 // we are creating here gets a chance to have its code optimized and
1093 // doesn't just get a copy of the existing unoptimized code.
1094 if (!FLAG_always_opt &&
1095 !FLAG_prepare_always_opt &&
1096 scope()->is_function_scope() &&
1012 info->num_literals() == 0 && 1097 info->num_literals() == 0 &&
1013 !pretenure) { 1098 !pretenure) {
1014 FastNewClosureStub stub; 1099 FastNewClosureStub stub;
1015 __ mov(r0, Operand(info)); 1100 __ mov(r0, Operand(info));
1016 __ push(r0); 1101 __ push(r0);
1017 __ CallStub(&stub); 1102 __ CallStub(&stub);
1018 } else { 1103 } else {
1019 __ mov(r0, Operand(info)); 1104 __ mov(r0, Operand(info));
1020 __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex 1105 __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex
1021 : Heap::kFalseValueRootIndex); 1106 : Heap::kFalseValueRootIndex);
1022 __ Push(cp, r0, r1); 1107 __ Push(cp, r0, r1);
1023 __ CallRuntime(Runtime::kNewClosure, 3); 1108 __ CallRuntime(Runtime::kNewClosure, 3);
1024 } 1109 }
1025 context()->Plug(r0); 1110 context()->Plug(r0);
1026 } 1111 }
1027 1112
1028 1113
1029 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { 1114 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1030 Comment cmnt(masm_, "[ VariableProxy"); 1115 Comment cmnt(masm_, "[ VariableProxy");
1031 EmitVariableLoad(expr->var()); 1116 EmitVariableLoad(expr->var());
1032 } 1117 }
1033 1118
1034 1119
1035 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( 1120 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
1036 Slot* slot, 1121 Slot* slot,
1037 Label* slow) { 1122 Label* slow) {
1038 ASSERT(slot->type() == Slot::CONTEXT); 1123 ASSERT(slot->type() == Slot::CONTEXT);
1039 Register current = cp; 1124 Register context = cp;
1040 Register next = r3; 1125 Register next = r3;
1041 Register temp = r4; 1126 Register temp = r4;
1042 1127
1043 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { 1128 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
1044 if (s->num_heap_slots() > 0) { 1129 if (s->num_heap_slots() > 0) {
1045 if (s->calls_eval()) { 1130 if (s->calls_eval()) {
1046 // Check that extension is NULL. 1131 // Check that extension is NULL.
1047 __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX)); 1132 __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
1048 __ tst(temp, temp); 1133 __ tst(temp, temp);
1049 __ b(ne, slow); 1134 __ b(ne, slow);
1050 } 1135 }
1051 __ ldr(next, ContextOperand(current, Context::CLOSURE_INDEX)); 1136 __ ldr(next, ContextOperand(context, Context::CLOSURE_INDEX));
1052 __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset)); 1137 __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset));
1053 // Walk the rest of the chain without clobbering cp. 1138 // Walk the rest of the chain without clobbering cp.
1054 current = next; 1139 context = next;
1055 } 1140 }
1056 } 1141 }
1057 // Check that last extension is NULL. 1142 // Check that last extension is NULL.
1058 __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX)); 1143 __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
1059 __ tst(temp, temp); 1144 __ tst(temp, temp);
1060 __ b(ne, slow); 1145 __ b(ne, slow);
1061 __ ldr(temp, ContextOperand(current, Context::FCONTEXT_INDEX)); 1146
1062 return ContextOperand(temp, slot->index()); 1147 // This function is used only for loads, not stores, so it's safe to
1148 // return an cp-based operand (the write barrier cannot be allowed to
1149 // destroy the cp register).
1150 return ContextOperand(context, slot->index());
1063 } 1151 }
1064 1152
1065 1153
1066 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( 1154 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1067 Slot* slot, 1155 Slot* slot,
1068 TypeofState typeof_state, 1156 TypeofState typeof_state,
1069 Label* slow, 1157 Label* slow,
1070 Label* done) { 1158 Label* done) {
1071 // Generate fast-case code for variables that might be shadowed by 1159 // Generate fast-case code for variables that might be shadowed by
1072 // eval-introduced variables. Eval is used a lot without 1160 // eval-introduced variables. Eval is used a lot without
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
1252 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1340 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1253 context()->Plug(r0); 1341 context()->Plug(r0);
1254 } 1342 }
1255 } 1343 }
1256 1344
1257 1345
1258 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { 1346 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1259 Comment cmnt(masm_, "[ RegExpLiteral"); 1347 Comment cmnt(masm_, "[ RegExpLiteral");
1260 Label materialized; 1348 Label materialized;
1261 // Registers will be used as follows: 1349 // Registers will be used as follows:
1350 // r5 = materialized value (RegExp literal)
1262 // r4 = JS function, literals array 1351 // r4 = JS function, literals array
1263 // r3 = literal index 1352 // r3 = literal index
1264 // r2 = RegExp pattern 1353 // r2 = RegExp pattern
1265 // r1 = RegExp flags 1354 // r1 = RegExp flags
1266 // r0 = temp + materialized value (RegExp literal) 1355 // r0 = RegExp literal clone
1267 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1356 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1268 __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); 1357 __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
1269 int literal_offset = 1358 int literal_offset =
1270 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; 1359 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
1271 __ ldr(r0, FieldMemOperand(r4, literal_offset)); 1360 __ ldr(r5, FieldMemOperand(r4, literal_offset));
1272 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 1361 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1273 __ cmp(r0, ip); 1362 __ cmp(r5, ip);
1274 __ b(ne, &materialized); 1363 __ b(ne, &materialized);
1275 1364
1276 // Create regexp literal using runtime function. 1365 // Create regexp literal using runtime function.
1277 // Result will be in r0. 1366 // Result will be in r0.
1278 __ mov(r3, Operand(Smi::FromInt(expr->literal_index()))); 1367 __ mov(r3, Operand(Smi::FromInt(expr->literal_index())));
1279 __ mov(r2, Operand(expr->pattern())); 1368 __ mov(r2, Operand(expr->pattern()));
1280 __ mov(r1, Operand(expr->flags())); 1369 __ mov(r1, Operand(expr->flags()));
1281 __ Push(r4, r3, r2, r1); 1370 __ Push(r4, r3, r2, r1);
1282 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); 1371 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
1372 __ mov(r5, r0);
1283 1373
1284 __ bind(&materialized); 1374 __ bind(&materialized);
1285 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; 1375 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1286 __ push(r0); 1376 Label allocated, runtime_allocate;
1377 __ AllocateInNewSpace(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT);
1378 __ jmp(&allocated);
1379
1380 __ bind(&runtime_allocate);
1381 __ push(r5);
1287 __ mov(r0, Operand(Smi::FromInt(size))); 1382 __ mov(r0, Operand(Smi::FromInt(size)));
1288 __ push(r0); 1383 __ push(r0);
1289 __ CallRuntime(Runtime::kAllocateInNewSpace, 1); 1384 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1385 __ pop(r5);
1290 1386
1387 __ bind(&allocated);
1291 // After this, registers are used as follows: 1388 // After this, registers are used as follows:
1292 // r0: Newly allocated regexp. 1389 // r0: Newly allocated regexp.
1293 // r1: Materialized regexp. 1390 // r5: Materialized regexp.
1294 // r2: temp. 1391 // r2: temp.
1295 __ pop(r1); 1392 __ CopyFields(r0, r5, r2.bit(), size / kPointerSize);
1296 __ CopyFields(r0, r1, r2.bit(), size / kPointerSize);
1297 context()->Plug(r0); 1393 context()->Plug(r0);
1298 } 1394 }
1299 1395
1300 1396
1301 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { 1397 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1302 Comment cmnt(masm_, "[ ObjectLiteral"); 1398 Comment cmnt(masm_, "[ ObjectLiteral");
1303 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1399 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1304 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); 1400 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
1305 __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); 1401 __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
1306 __ mov(r1, Operand(expr->constant_properties())); 1402 __ mov(r1, Operand(expr->constant_properties()));
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1352 break; 1448 break;
1353 } 1449 }
1354 // Fall through. 1450 // Fall through.
1355 case ObjectLiteral::Property::PROTOTYPE: 1451 case ObjectLiteral::Property::PROTOTYPE:
1356 // Duplicate receiver on stack. 1452 // Duplicate receiver on stack.
1357 __ ldr(r0, MemOperand(sp)); 1453 __ ldr(r0, MemOperand(sp));
1358 __ push(r0); 1454 __ push(r0);
1359 VisitForStackValue(key); 1455 VisitForStackValue(key);
1360 VisitForStackValue(value); 1456 VisitForStackValue(value);
1361 if (property->emit_store()) { 1457 if (property->emit_store()) {
1362 __ CallRuntime(Runtime::kSetProperty, 3); 1458 __ mov(r0, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1459 __ push(r0);
1460 __ CallRuntime(Runtime::kSetProperty, 4);
1363 } else { 1461 } else {
1364 __ Drop(3); 1462 __ Drop(3);
1365 } 1463 }
1366 break; 1464 break;
1367 case ObjectLiteral::Property::GETTER: 1465 case ObjectLiteral::Property::GETTER:
1368 case ObjectLiteral::Property::SETTER: 1466 case ObjectLiteral::Property::SETTER:
1369 // Duplicate receiver on stack. 1467 // Duplicate receiver on stack.
1370 __ ldr(r0, MemOperand(sp)); 1468 __ ldr(r0, MemOperand(sp));
1371 __ push(r0); 1469 __ push(r0);
1372 VisitForStackValue(key); 1470 VisitForStackValue(key);
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
1532 } 1630 }
1533 } 1631 }
1534 1632
1535 // For property compound assignments we need another deoptimization 1633 // For property compound assignments we need another deoptimization
1536 // point after the property load. 1634 // point after the property load.
1537 if (property != NULL) { 1635 if (property != NULL) {
1538 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); 1636 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
1539 } 1637 }
1540 1638
1541 Token::Value op = expr->binary_op(); 1639 Token::Value op = expr->binary_op();
1542 ConstantOperand constant = ShouldInlineSmiCase(op) 1640 __ push(r0); // Left operand goes on the stack.
1543 ? GetConstantOperand(op, expr->target(), expr->value()) 1641 VisitForAccumulatorValue(expr->value());
1544 : kNoConstants;
1545 ASSERT(constant == kRightConstant || constant == kNoConstants);
1546 if (constant == kNoConstants) {
1547 __ push(r0); // Left operand goes on the stack.
1548 VisitForAccumulatorValue(expr->value());
1549 }
1550 1642
1551 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() 1643 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1552 ? OVERWRITE_RIGHT 1644 ? OVERWRITE_RIGHT
1553 : NO_OVERWRITE; 1645 : NO_OVERWRITE;
1554 SetSourcePosition(expr->position() + 1); 1646 SetSourcePosition(expr->position() + 1);
1555 AccumulatorValueContext context(this); 1647 AccumulatorValueContext context(this);
1556 if (ShouldInlineSmiCase(op)) { 1648 if (ShouldInlineSmiCase(op)) {
1557 EmitInlineSmiBinaryOp(expr, 1649 EmitInlineSmiBinaryOp(expr,
1558 op, 1650 op,
1559 mode, 1651 mode,
1560 expr->target(), 1652 expr->target(),
1561 expr->value(), 1653 expr->value());
1562 constant);
1563 } else { 1654 } else {
1564 EmitBinaryOp(op, mode); 1655 EmitBinaryOp(op, mode);
1565 } 1656 }
1566 1657
1567 // Deoptimization point in case the binary operation may have side effects. 1658 // Deoptimization point in case the binary operation may have side effects.
1568 PrepareForBailout(expr->binary_operation(), TOS_REG); 1659 PrepareForBailout(expr->binary_operation(), TOS_REG);
1569 } else { 1660 } else {
1570 VisitForAccumulatorValue(expr->value()); 1661 VisitForAccumulatorValue(expr->value());
1571 } 1662 }
1572 1663
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1605 SetSourcePosition(prop->position()); 1696 SetSourcePosition(prop->position());
1606 // Call keyed load IC. It has arguments key and receiver in r0 and r1. 1697 // Call keyed load IC. It has arguments key and receiver in r0 and r1.
1607 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 1698 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1608 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1699 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1609 } 1700 }
1610 1701
1611 1702
1612 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, 1703 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
1613 Token::Value op, 1704 Token::Value op,
1614 OverwriteMode mode, 1705 OverwriteMode mode,
1615 Expression* left, 1706 Expression* left_expr,
1616 Expression* right, 1707 Expression* right_expr) {
1617 ConstantOperand constant) { 1708 Label done, smi_case, stub_call;
1618 ASSERT(constant == kNoConstants); // Only handled case. 1709
1619 EmitBinaryOp(op, mode); 1710 Register scratch1 = r2;
1711 Register scratch2 = r3;
1712
1713 // Get the arguments.
1714 Register left = r1;
1715 Register right = r0;
1716 __ pop(left);
1717
1718 // Perform combined smi check on both operands.
1719 __ orr(scratch1, left, Operand(right));
1720 STATIC_ASSERT(kSmiTag == 0);
1721 JumpPatchSite patch_site(masm_);
1722 patch_site.EmitJumpIfSmi(scratch1, &smi_case);
1723
1724 __ bind(&stub_call);
1725 TypeRecordingBinaryOpStub stub(op, mode);
1726 EmitCallIC(stub.GetCode(), &patch_site);
1727 __ jmp(&done);
1728
1729 __ bind(&smi_case);
1730 // Smi case. This code works the same way as the smi-smi case in the type
1731 // recording binary operation stub, see
1732 // TypeRecordingBinaryOpStub::GenerateSmiSmiOperation for comments.
1733 switch (op) {
1734 case Token::SAR:
1735 __ b(&stub_call);
1736 __ GetLeastBitsFromSmi(scratch1, right, 5);
1737 __ mov(right, Operand(left, ASR, scratch1));
1738 __ bic(right, right, Operand(kSmiTagMask));
1739 break;
1740 case Token::SHL: {
1741 __ b(&stub_call);
1742 __ SmiUntag(scratch1, left);
1743 __ GetLeastBitsFromSmi(scratch2, right, 5);
1744 __ mov(scratch1, Operand(scratch1, LSL, scratch2));
1745 __ add(scratch2, scratch1, Operand(0x40000000), SetCC);
1746 __ b(mi, &stub_call);
1747 __ SmiTag(right, scratch1);
1748 break;
1749 }
1750 case Token::SHR: {
1751 __ b(&stub_call);
1752 __ SmiUntag(scratch1, left);
1753 __ GetLeastBitsFromSmi(scratch2, right, 5);
1754 __ mov(scratch1, Operand(scratch1, LSR, scratch2));
1755 __ tst(scratch1, Operand(0xc0000000));
1756 __ b(ne, &stub_call);
1757 __ SmiTag(right, scratch1);
1758 break;
1759 }
1760 case Token::ADD:
1761 __ add(scratch1, left, Operand(right), SetCC);
1762 __ b(vs, &stub_call);
1763 __ mov(right, scratch1);
1764 break;
1765 case Token::SUB:
1766 __ sub(scratch1, left, Operand(right), SetCC);
1767 __ b(vs, &stub_call);
1768 __ mov(right, scratch1);
1769 break;
1770 case Token::MUL: {
1771 __ SmiUntag(ip, right);
1772 __ smull(scratch1, scratch2, left, ip);
1773 __ mov(ip, Operand(scratch1, ASR, 31));
1774 __ cmp(ip, Operand(scratch2));
1775 __ b(ne, &stub_call);
1776 __ tst(scratch1, Operand(scratch1));
1777 __ mov(right, Operand(scratch1), LeaveCC, ne);
1778 __ b(ne, &done);
1779 __ add(scratch2, right, Operand(left), SetCC);
1780 __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl);
1781 __ b(mi, &stub_call);
1782 break;
1783 }
1784 case Token::BIT_OR:
1785 __ orr(right, left, Operand(right));
1786 break;
1787 case Token::BIT_AND:
1788 __ and_(right, left, Operand(right));
1789 break;
1790 case Token::BIT_XOR:
1791 __ eor(right, left, Operand(right));
1792 break;
1793 default:
1794 UNREACHABLE();
1795 }
1796
1797 __ bind(&done);
1798 context()->Plug(r0);
1620 } 1799 }
1621 1800
1622 1801
1623 void FullCodeGenerator::EmitBinaryOp(Token::Value op, 1802 void FullCodeGenerator::EmitBinaryOp(Token::Value op,
1624 OverwriteMode mode) { 1803 OverwriteMode mode) {
1625 __ pop(r1); 1804 __ pop(r1);
1626 TypeRecordingBinaryOpStub stub(op, mode); 1805 TypeRecordingBinaryOpStub stub(op, mode);
1627 EmitCallIC(stub.GetCode(), NULL); 1806 EmitCallIC(stub.GetCode(), NULL);
1628 context()->Plug(r0); 1807 context()->Plug(r0);
1629 } 1808 }
(...skipping 24 matching lines...) Expand all
1654 EffectContext context(this); 1833 EffectContext context(this);
1655 EmitVariableAssignment(var, Token::ASSIGN); 1834 EmitVariableAssignment(var, Token::ASSIGN);
1656 break; 1835 break;
1657 } 1836 }
1658 case NAMED_PROPERTY: { 1837 case NAMED_PROPERTY: {
1659 __ push(r0); // Preserve value. 1838 __ push(r0); // Preserve value.
1660 VisitForAccumulatorValue(prop->obj()); 1839 VisitForAccumulatorValue(prop->obj());
1661 __ mov(r1, r0); 1840 __ mov(r1, r0);
1662 __ pop(r0); // Restore value. 1841 __ pop(r0); // Restore value.
1663 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); 1842 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
1664 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 1843 Handle<Code> ic(Builtins::builtin(
1844 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
1845 : Builtins::StoreIC_Initialize));
1665 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1846 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1666 break; 1847 break;
1667 } 1848 }
1668 case KEYED_PROPERTY: { 1849 case KEYED_PROPERTY: {
1669 __ push(r0); // Preserve value. 1850 __ push(r0); // Preserve value.
1670 if (prop->is_synthetic()) { 1851 if (prop->is_synthetic()) {
1671 ASSERT(prop->obj()->AsVariableProxy() != NULL); 1852 ASSERT(prop->obj()->AsVariableProxy() != NULL);
1672 ASSERT(prop->key()->AsLiteral() != NULL); 1853 ASSERT(prop->key()->AsLiteral() != NULL);
1673 { AccumulatorValueContext for_object(this); 1854 { AccumulatorValueContext for_object(this);
1674 EmitVariableLoad(prop->obj()->AsVariableProxy()->var()); 1855 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
1675 } 1856 }
1676 __ mov(r2, r0); 1857 __ mov(r2, r0);
1677 __ mov(r1, Operand(prop->key()->AsLiteral()->handle())); 1858 __ mov(r1, Operand(prop->key()->AsLiteral()->handle()));
1678 } else { 1859 } else {
1679 VisitForStackValue(prop->obj()); 1860 VisitForStackValue(prop->obj());
1680 VisitForAccumulatorValue(prop->key()); 1861 VisitForAccumulatorValue(prop->key());
1681 __ mov(r1, r0); 1862 __ mov(r1, r0);
1682 __ pop(r2); 1863 __ pop(r2);
1683 } 1864 }
1684 __ pop(r0); // Restore value. 1865 __ pop(r0); // Restore value.
1685 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 1866 Handle<Code> ic(Builtins::builtin(
1867 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict
1868 : Builtins::KeyedStoreIC_Initialize));
1686 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1869 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1687 break; 1870 break;
1688 } 1871 }
1689 } 1872 }
1690 PrepareForBailoutForId(bailout_ast_id, TOS_REG); 1873 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1691 context()->Plug(r0); 1874 context()->Plug(r0);
1692 } 1875 }
1693 1876
1694 1877
1695 void FullCodeGenerator::EmitVariableAssignment(Variable* var, 1878 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
1696 Token::Value op) { 1879 Token::Value op) {
1697 // Left-hand sides that rewrite to explicit property accesses do not reach 1880 // Left-hand sides that rewrite to explicit property accesses do not reach
1698 // here. 1881 // here.
1699 ASSERT(var != NULL); 1882 ASSERT(var != NULL);
1700 ASSERT(var->is_global() || var->AsSlot() != NULL); 1883 ASSERT(var->is_global() || var->AsSlot() != NULL);
1701 1884
1702 if (var->is_global()) { 1885 if (var->is_global()) {
1703 ASSERT(!var->is_this()); 1886 ASSERT(!var->is_this());
1704 // Assignment to a global variable. Use inline caching for the 1887 // Assignment to a global variable. Use inline caching for the
1705 // assignment. Right-hand-side value is passed in r0, variable name in 1888 // assignment. Right-hand-side value is passed in r0, variable name in
1706 // r2, and the global object in r1. 1889 // r2, and the global object in r1.
1707 __ mov(r2, Operand(var->name())); 1890 __ mov(r2, Operand(var->name()));
1708 __ ldr(r1, GlobalObjectOperand()); 1891 __ ldr(r1, GlobalObjectOperand());
1709 Handle<Code> ic(Builtins::builtin(is_strict() 1892 Handle<Code> ic(Builtins::builtin(
1710 ? Builtins::StoreIC_Initialize_Strict 1893 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
1711 : Builtins::StoreIC_Initialize)); 1894 : Builtins::StoreIC_Initialize));
1712 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); 1895 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
1713 1896
1714 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { 1897 } else if (op == Token::INIT_CONST) {
1715 // Perform the assignment for non-const variables and for initialization 1898 // Like var declarations, const declarations are hoisted to function
1716 // of const variables. Const assignments are simply skipped. 1899 // scope. However, unlike var initializers, const initializers are able
1717 Label done; 1900 // to drill a hole to that function context, even from inside a 'with'
1901 // context. We thus bypass the normal static scope lookup.
1902 Slot* slot = var->AsSlot();
1903 Label skip;
1904 switch (slot->type()) {
1905 case Slot::PARAMETER:
1906 // No const parameters.
1907 UNREACHABLE();
1908 break;
1909 case Slot::LOCAL:
1910 // Detect const reinitialization by checking for the hole value.
1911 __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
1912 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1913 __ cmp(r1, ip);
1914 __ b(ne, &skip);
1915 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
1916 break;
1917 case Slot::CONTEXT: {
1918 __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX));
1919 __ ldr(r2, ContextOperand(r1, slot->index()));
1920 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1921 __ cmp(r2, ip);
1922 __ b(ne, &skip);
1923 __ str(r0, ContextOperand(r1, slot->index()));
1924 int offset = Context::SlotOffset(slot->index());
1925 __ mov(r3, r0); // Preserve the stored value in r0.
1926 __ RecordWrite(r1, Operand(offset), r3, r2);
1927 break;
1928 }
1929 case Slot::LOOKUP:
1930 __ push(r0);
1931 __ mov(r0, Operand(slot->var()->name()));
1932 __ Push(cp, r0); // Context and name.
1933 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1934 break;
1935 }
1936 __ bind(&skip);
1937
1938 } else if (var->mode() != Variable::CONST) {
1939 // Perform the assignment for non-const variables. Const assignments
1940 // are simply skipped.
1718 Slot* slot = var->AsSlot(); 1941 Slot* slot = var->AsSlot();
1719 switch (slot->type()) { 1942 switch (slot->type()) {
1720 case Slot::PARAMETER: 1943 case Slot::PARAMETER:
1721 case Slot::LOCAL: 1944 case Slot::LOCAL:
1722 if (op == Token::INIT_CONST) {
1723 // Detect const reinitialization by checking for the hole value.
1724 __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
1725 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1726 __ cmp(r1, ip);
1727 __ b(ne, &done);
1728 }
1729 // Perform the assignment. 1945 // Perform the assignment.
1730 __ str(result_register(), MemOperand(fp, SlotOffset(slot))); 1946 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
1731 break; 1947 break;
1732 1948
1733 case Slot::CONTEXT: { 1949 case Slot::CONTEXT: {
1734 MemOperand target = EmitSlotSearch(slot, r1); 1950 MemOperand target = EmitSlotSearch(slot, r1);
1735 if (op == Token::INIT_CONST) {
1736 // Detect const reinitialization by checking for the hole value.
1737 __ ldr(r2, target);
1738 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1739 __ cmp(r2, ip);
1740 __ b(ne, &done);
1741 }
1742 // Perform the assignment and issue the write barrier. 1951 // Perform the assignment and issue the write barrier.
1743 __ str(result_register(), target); 1952 __ str(result_register(), target);
1744 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER 1953 #ifdef ENABLE_CARDMARKING_WRITE_BARRIER
1745 // RecordWrite may destroy all its register arguments. 1954 // RecordWrite may destroy all its register arguments.
1746 __ mov(r3, result_register()); 1955 __ mov(r3, result_register());
1747 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 1956 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
1748 __ RecordWrite(r1, Operand(offset), r2, r3); 1957 __ RecordWrite(r1, Operand(offset), r2, r3);
1749 #endif 1958 #endif
1750 break; 1959 break;
1751 } 1960 }
1752 1961
1753 case Slot::LOOKUP: 1962 case Slot::LOOKUP:
1754 // Call the runtime for the assignment. The runtime will ignore 1963 // Call the runtime for the assignment.
1755 // const reinitialization.
1756 __ push(r0); // Value. 1964 __ push(r0); // Value.
1757 __ mov(r0, Operand(slot->var()->name())); 1965 __ mov(r1, Operand(slot->var()->name()));
1758 __ Push(cp, r0); // Context and name. 1966 __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
1759 if (op == Token::INIT_CONST) { 1967 __ Push(cp, r1, r0); // Context, name, strict mode.
1760 // The runtime will ignore const redeclaration. 1968 __ CallRuntime(Runtime::kStoreContextSlot, 4);
1761 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1762 } else {
1763 __ CallRuntime(Runtime::kStoreContextSlot, 3);
1764 }
1765 break; 1969 break;
1766 } 1970 }
1767 __ bind(&done);
1768 } 1971 }
1769 } 1972 }
1770 1973
1771 1974
1772 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { 1975 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1773 // Assignment to a property, using a named store IC. 1976 // Assignment to a property, using a named store IC.
1774 Property* prop = expr->target()->AsProperty(); 1977 Property* prop = expr->target()->AsProperty();
1775 ASSERT(prop != NULL); 1978 ASSERT(prop != NULL);
1776 ASSERT(prop->key()->AsLiteral() != NULL); 1979 ASSERT(prop->key()->AsLiteral() != NULL);
1777 1980
(...skipping 12 matching lines...) Expand all
1790 SetSourcePosition(expr->position()); 1993 SetSourcePosition(expr->position());
1791 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); 1994 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
1792 // Load receiver to r1. Leave a copy in the stack if needed for turning the 1995 // Load receiver to r1. Leave a copy in the stack if needed for turning the
1793 // receiver into fast case. 1996 // receiver into fast case.
1794 if (expr->ends_initialization_block()) { 1997 if (expr->ends_initialization_block()) {
1795 __ ldr(r1, MemOperand(sp)); 1998 __ ldr(r1, MemOperand(sp));
1796 } else { 1999 } else {
1797 __ pop(r1); 2000 __ pop(r1);
1798 } 2001 }
1799 2002
1800 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 2003 Handle<Code> ic(Builtins::builtin(
2004 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
2005 : Builtins::StoreIC_Initialize));
1801 EmitCallIC(ic, RelocInfo::CODE_TARGET); 2006 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1802 2007
1803 // If the assignment ends an initialization block, revert to fast case. 2008 // If the assignment ends an initialization block, revert to fast case.
1804 if (expr->ends_initialization_block()) { 2009 if (expr->ends_initialization_block()) {
1805 __ push(r0); // Result of assignment, saved even if not needed. 2010 __ push(r0); // Result of assignment, saved even if not needed.
1806 // Receiver is under the result value. 2011 // Receiver is under the result value.
1807 __ ldr(ip, MemOperand(sp, kPointerSize)); 2012 __ ldr(ip, MemOperand(sp, kPointerSize));
1808 __ push(ip); 2013 __ push(ip);
1809 __ CallRuntime(Runtime::kToFastProperties, 1); 2014 __ CallRuntime(Runtime::kToFastProperties, 1);
1810 __ pop(r0); 2015 __ pop(r0);
(...skipping 23 matching lines...) Expand all
1834 SetSourcePosition(expr->position()); 2039 SetSourcePosition(expr->position());
1835 __ pop(r1); // Key. 2040 __ pop(r1); // Key.
1836 // Load receiver to r2. Leave a copy in the stack if needed for turning the 2041 // Load receiver to r2. Leave a copy in the stack if needed for turning the
1837 // receiver into fast case. 2042 // receiver into fast case.
1838 if (expr->ends_initialization_block()) { 2043 if (expr->ends_initialization_block()) {
1839 __ ldr(r2, MemOperand(sp)); 2044 __ ldr(r2, MemOperand(sp));
1840 } else { 2045 } else {
1841 __ pop(r2); 2046 __ pop(r2);
1842 } 2047 }
1843 2048
1844 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 2049 Handle<Code> ic(Builtins::builtin(
2050 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict
2051 : Builtins::KeyedStoreIC_Initialize));
1845 EmitCallIC(ic, RelocInfo::CODE_TARGET); 2052 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1846 2053
1847 // If the assignment ends an initialization block, revert to fast case. 2054 // If the assignment ends an initialization block, revert to fast case.
1848 if (expr->ends_initialization_block()) { 2055 if (expr->ends_initialization_block()) {
1849 __ push(r0); // Result of assignment, saved even if not needed. 2056 __ push(r0); // Result of assignment, saved even if not needed.
1850 // Receiver is under the result value. 2057 // Receiver is under the result value.
1851 __ ldr(ip, MemOperand(sp, kPointerSize)); 2058 __ ldr(ip, MemOperand(sp, kPointerSize));
1852 __ push(ip); 2059 __ push(ip);
1853 __ CallRuntime(Runtime::kToFastProperties, 1); 2060 __ CallRuntime(Runtime::kToFastProperties, 1);
1854 __ pop(r0); 2061 __ pop(r0);
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
1949 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; 2156 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1950 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); 2157 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1951 __ CallStub(&stub); 2158 __ CallStub(&stub);
1952 RecordJSReturnSite(expr); 2159 RecordJSReturnSite(expr);
1953 // Restore context register. 2160 // Restore context register.
1954 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 2161 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1955 context()->DropAndPlug(1, r0); 2162 context()->DropAndPlug(1, r0);
1956 } 2163 }
1957 2164
1958 2165
2166 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
2167 int arg_count) {
2168 // Push copy of the first argument or undefined if it doesn't exist.
2169 if (arg_count > 0) {
2170 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
2171 } else {
2172 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
2173 }
2174 __ push(r1);
2175
2176 // Push the receiver of the enclosing function and do runtime call.
2177 __ ldr(r1, MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
2178 __ push(r1);
2179 // Push the strict mode flag.
2180 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
2181 __ push(r1);
2182
2183 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2184 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2185 : Runtime::kResolvePossiblyDirectEval, 4);
2186 }
2187
2188
1959 void FullCodeGenerator::VisitCall(Call* expr) { 2189 void FullCodeGenerator::VisitCall(Call* expr) {
1960 #ifdef DEBUG 2190 #ifdef DEBUG
1961 // We want to verify that RecordJSReturnSite gets called on all paths 2191 // We want to verify that RecordJSReturnSite gets called on all paths
1962 // through this function. Avoid early returns. 2192 // through this function. Avoid early returns.
1963 expr->return_is_recorded_ = false; 2193 expr->return_is_recorded_ = false;
1964 #endif 2194 #endif
1965 2195
1966 Comment cmnt(masm_, "[ Call"); 2196 Comment cmnt(masm_, "[ Call");
1967 Expression* fun = expr->expression(); 2197 Expression* fun = expr->expression();
1968 Variable* var = fun->AsVariableProxy()->AsVariable(); 2198 Variable* var = fun->AsVariableProxy()->AsVariable();
1969 2199
1970 if (var != NULL && var->is_possibly_eval()) { 2200 if (var != NULL && var->is_possibly_eval()) {
1971 // In a call to eval, we first call %ResolvePossiblyDirectEval to 2201 // In a call to eval, we first call %ResolvePossiblyDirectEval to
1972 // resolve the function we need to call and the receiver of the 2202 // resolve the function we need to call and the receiver of the
1973 // call. Then we call the resolved function using the given 2203 // call. Then we call the resolved function using the given
1974 // arguments. 2204 // arguments.
1975 ZoneList<Expression*>* args = expr->arguments(); 2205 ZoneList<Expression*>* args = expr->arguments();
1976 int arg_count = args->length(); 2206 int arg_count = args->length();
1977 2207
1978 { PreservePositionScope pos_scope(masm()->positions_recorder()); 2208 { PreservePositionScope pos_scope(masm()->positions_recorder());
1979 VisitForStackValue(fun); 2209 VisitForStackValue(fun);
1980 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); 2210 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
1981 __ push(r2); // Reserved receiver slot. 2211 __ push(r2); // Reserved receiver slot.
1982 2212
1983 // Push the arguments. 2213 // Push the arguments.
1984 for (int i = 0; i < arg_count; i++) { 2214 for (int i = 0; i < arg_count; i++) {
1985 VisitForStackValue(args->at(i)); 2215 VisitForStackValue(args->at(i));
1986 } 2216 }
1987 2217
1988 // Push copy of the function - found below the arguments. 2218 // If we know that eval can only be shadowed by eval-introduced
2219 // variables we attempt to load the global eval function directly
2220 // in generated code. If we succeed, there is no need to perform a
2221 // context lookup in the runtime system.
2222 Label done;
2223 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
2224 Label slow;
2225 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
2226 NOT_INSIDE_TYPEOF,
2227 &slow);
2228 // Push the function and resolve eval.
2229 __ push(r0);
2230 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2231 __ jmp(&done);
2232 __ bind(&slow);
2233 }
2234
2235 // Push copy of the function (found below the arguments) and
2236 // resolve eval.
1989 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); 2237 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
1990 __ push(r1); 2238 __ push(r1);
1991 2239 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
1992 // Push copy of the first argument or undefined if it doesn't exist. 2240 if (done.is_linked()) {
1993 if (arg_count > 0) { 2241 __ bind(&done);
1994 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
1995 __ push(r1);
1996 } else {
1997 __ push(r2);
1998 } 2242 }
1999 2243
2000 // Push the receiver of the enclosing function and do runtime call.
2001 __ ldr(r1,
2002 MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
2003 __ push(r1);
2004 // Push the strict mode flag.
2005 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
2006 __ push(r1);
2007 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4);
2008
2009 // The runtime call returns a pair of values in r0 (function) and 2244 // The runtime call returns a pair of values in r0 (function) and
2010 // r1 (receiver). Touch up the stack with the right values. 2245 // r1 (receiver). Touch up the stack with the right values.
2011 __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize)); 2246 __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
2012 __ str(r1, MemOperand(sp, arg_count * kPointerSize)); 2247 __ str(r1, MemOperand(sp, arg_count * kPointerSize));
2013 } 2248 }
2014 2249
2015 // Record source position for debugger. 2250 // Record source position for debugger.
2016 SetSourcePosition(expr->position()); 2251 SetSourcePosition(expr->position());
2017 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; 2252 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2018 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); 2253 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
(...skipping 611 matching lines...) Expand 10 before | Expand all | Expand 10 after
2630 __ bind(&done); 2865 __ bind(&done);
2631 context()->Plug(r0); 2866 context()->Plug(r0);
2632 } 2867 }
2633 2868
2634 2869
2635 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) { 2870 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2636 // Load the arguments on the stack and call the runtime function. 2871 // Load the arguments on the stack and call the runtime function.
2637 ASSERT(args->length() == 2); 2872 ASSERT(args->length() == 2);
2638 VisitForStackValue(args->at(0)); 2873 VisitForStackValue(args->at(0));
2639 VisitForStackValue(args->at(1)); 2874 VisitForStackValue(args->at(1));
2640 __ CallRuntime(Runtime::kMath_pow, 2); 2875 MathPowStub stub;
2876 __ CallStub(&stub);
2641 context()->Plug(r0); 2877 context()->Plug(r0);
2642 } 2878 }
2643 2879
2644 2880
2645 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) { 2881 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2646 ASSERT(args->length() == 2); 2882 ASSERT(args->length() == 2);
2647 2883
2648 VisitForStackValue(args->at(0)); // Load the object. 2884 VisitForStackValue(args->at(0)); // Load the object.
2649 VisitForAccumulatorValue(args->at(1)); // Load the value. 2885 VisitForAccumulatorValue(args->at(1)); // Load the value.
2650 __ pop(r1); // r0 = value. r1 = object. 2886 __ pop(r1); // r0 = value. r1 = object.
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
2814 VisitForStackValue(args->at(0)); 3050 VisitForStackValue(args->at(0));
2815 VisitForStackValue(args->at(1)); 3051 VisitForStackValue(args->at(1));
2816 3052
2817 StringCompareStub stub; 3053 StringCompareStub stub;
2818 __ CallStub(&stub); 3054 __ CallStub(&stub);
2819 context()->Plug(r0); 3055 context()->Plug(r0);
2820 } 3056 }
2821 3057
2822 3058
2823 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) { 3059 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2824 // Load the argument on the stack and call the runtime. 3060 // Load the argument on the stack and call the stub.
3061 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3062 TranscendentalCacheStub::TAGGED);
2825 ASSERT(args->length() == 1); 3063 ASSERT(args->length() == 1);
2826 VisitForStackValue(args->at(0)); 3064 VisitForStackValue(args->at(0));
2827 __ CallRuntime(Runtime::kMath_sin, 1); 3065 __ CallStub(&stub);
2828 context()->Plug(r0); 3066 context()->Plug(r0);
2829 } 3067 }
2830 3068
2831 3069
2832 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) { 3070 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2833 // Load the argument on the stack and call the runtime. 3071 // Load the argument on the stack and call the stub.
3072 TranscendentalCacheStub stub(TranscendentalCache::COS,
3073 TranscendentalCacheStub::TAGGED);
2834 ASSERT(args->length() == 1); 3074 ASSERT(args->length() == 1);
2835 VisitForStackValue(args->at(0)); 3075 VisitForStackValue(args->at(0));
2836 __ CallRuntime(Runtime::kMath_cos, 1); 3076 __ CallStub(&stub);
3077 context()->Plug(r0);
3078 }
3079
3080
3081 void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
3082 // Load the argument on the stack and call the stub.
3083 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3084 TranscendentalCacheStub::TAGGED);
3085 ASSERT(args->length() == 1);
3086 VisitForStackValue(args->at(0));
3087 __ CallStub(&stub);
2837 context()->Plug(r0); 3088 context()->Plug(r0);
2838 } 3089 }
2839 3090
2840 3091
2841 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) { 3092 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2842 // Load the argument on the stack and call the runtime function. 3093 // Load the argument on the stack and call the runtime function.
2843 ASSERT(args->length() == 1); 3094 ASSERT(args->length() == 1);
2844 VisitForStackValue(args->at(0)); 3095 VisitForStackValue(args->at(0));
2845 __ CallRuntime(Runtime::kMath_sqrt, 1); 3096 __ CallRuntime(Runtime::kMath_sqrt, 1);
2846 context()->Plug(r0); 3097 context()->Plug(r0);
2847 } 3098 }
2848 3099
2849
2850 void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
2851 // Load the argument on the stack and call the runtime function.
2852 ASSERT(args->length() == 1);
2853 VisitForStackValue(args->at(0));
2854 __ CallRuntime(Runtime::kMath_log, 1);
2855 context()->Plug(r0);
2856 }
2857
2858 3100
2859 void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) { 3101 void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
2860 ASSERT(args->length() >= 2); 3102 ASSERT(args->length() >= 2);
2861 3103
2862 int arg_count = args->length() - 2; // For receiver and function. 3104 int arg_count = args->length() - 2; // For receiver and function.
2863 VisitForStackValue(args->at(0)); // Receiver. 3105 VisitForStackValue(args->at(0)); // Receiver.
2864 for (int i = 0; i < arg_count; i++) { 3106 for (int i = 0; i < arg_count; i++) {
2865 VisitForStackValue(args->at(i + 1)); 3107 VisitForStackValue(args->at(i + 1));
2866 } 3108 }
2867 VisitForAccumulatorValue(args->at(arg_count + 1)); // Function. 3109 VisitForAccumulatorValue(args->at(arg_count + 1)); // Function.
(...skipping 16 matching lines...) Expand all
2884 __ CallStub(&stub); 3126 __ CallStub(&stub);
2885 context()->Plug(r0); 3127 context()->Plug(r0);
2886 } 3128 }
2887 3129
2888 3130
2889 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) { 3131 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2890 ASSERT(args->length() == 3); 3132 ASSERT(args->length() == 3);
2891 VisitForStackValue(args->at(0)); 3133 VisitForStackValue(args->at(0));
2892 VisitForStackValue(args->at(1)); 3134 VisitForStackValue(args->at(1));
2893 VisitForStackValue(args->at(2)); 3135 VisitForStackValue(args->at(2));
3136 Label done;
3137 Label slow_case;
3138 Register object = r0;
3139 Register index1 = r1;
3140 Register index2 = r2;
3141 Register elements = r3;
3142 Register scratch1 = r4;
3143 Register scratch2 = r5;
3144
3145 __ ldr(object, MemOperand(sp, 2 * kPointerSize));
3146 // Fetch the map and check if array is in fast case.
3147 // Check that object doesn't require security checks and
3148 // has no indexed interceptor.
3149 __ CompareObjectType(object, scratch1, scratch2, JS_ARRAY_TYPE);
3150 __ b(ne, &slow_case);
3151 // Map is now in scratch1.
3152
3153 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
3154 __ tst(scratch2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
3155 __ b(ne, &slow_case);
3156
3157 // Check the object's elements are in fast case and writable.
3158 __ ldr(elements, FieldMemOperand(object, JSObject::kElementsOffset));
3159 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
3160 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
3161 __ cmp(scratch1, ip);
3162 __ b(ne, &slow_case);
3163
3164 // Check that both indices are smis.
3165 __ ldr(index1, MemOperand(sp, 1 * kPointerSize));
3166 __ ldr(index2, MemOperand(sp, 0));
3167 __ JumpIfNotBothSmi(index1, index2, &slow_case);
3168
3169 // Check that both indices are valid.
3170 __ ldr(scratch1, FieldMemOperand(object, JSArray::kLengthOffset));
3171 __ cmp(scratch1, index1);
3172 __ cmp(scratch1, index2, hi);
3173 __ b(ls, &slow_case);
3174
3175 // Bring the address of the elements into index1 and index2.
3176 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3177 __ add(index1,
3178 scratch1,
3179 Operand(index1, LSL, kPointerSizeLog2 - kSmiTagSize));
3180 __ add(index2,
3181 scratch1,
3182 Operand(index2, LSL, kPointerSizeLog2 - kSmiTagSize));
3183
3184 // Swap elements.
3185 __ ldr(scratch1, MemOperand(index1, 0));
3186 __ ldr(scratch2, MemOperand(index2, 0));
3187 __ str(scratch1, MemOperand(index2, 0));
3188 __ str(scratch2, MemOperand(index1, 0));
3189
3190 Label new_space;
3191 __ InNewSpace(elements, scratch1, eq, &new_space);
3192 // Possible optimization: do a check that both values are Smis
3193 // (or them and test against Smi mask.)
3194
3195 __ mov(scratch1, elements);
3196 __ RecordWriteHelper(elements, index1, scratch2);
3197 __ RecordWriteHelper(scratch1, index2, scratch2); // scratch1 holds elements.
3198
3199 __ bind(&new_space);
3200 // We are done. Drop elements from the stack, and return undefined.
3201 __ Drop(3);
3202 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
3203 __ jmp(&done);
3204
3205 __ bind(&slow_case);
2894 __ CallRuntime(Runtime::kSwapElements, 3); 3206 __ CallRuntime(Runtime::kSwapElements, 3);
3207
3208 __ bind(&done);
2895 context()->Plug(r0); 3209 context()->Plug(r0);
2896 } 3210 }
2897 3211
2898 3212
2899 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) { 3213 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
2900 ASSERT_EQ(2, args->length()); 3214 ASSERT_EQ(2, args->length());
2901 3215
2902 ASSERT_NE(NULL, args->at(0)->AsLiteral()); 3216 ASSERT_NE(NULL, args->at(0)->AsLiteral());
2903 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value(); 3217 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
2904 3218
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
3003 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); 3317 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3004 Split(eq, if_true, if_false, fall_through); 3318 Split(eq, if_true, if_false, fall_through);
3005 3319
3006 context()->Plug(if_true, if_false); 3320 context()->Plug(if_true, if_false);
3007 } 3321 }
3008 3322
3009 3323
3010 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { 3324 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3011 ASSERT(args->length() == 1); 3325 ASSERT(args->length() == 1);
3012 VisitForAccumulatorValue(args->at(0)); 3326 VisitForAccumulatorValue(args->at(0));
3327
3328 if (FLAG_debug_code) {
3329 __ AbortIfNotString(r0);
3330 }
3331
3013 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); 3332 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
3014 __ IndexFromHash(r0, r0); 3333 __ IndexFromHash(r0, r0);
3334
3015 context()->Plug(r0); 3335 context()->Plug(r0);
3016 } 3336 }
3017 3337
3018 3338
3019 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { 3339 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
3340 Label bailout, done, one_char_separator, long_separator,
3341 non_trivial_array, not_size_one_array, loop,
3342 empty_separator_loop, one_char_separator_loop,
3343 one_char_separator_loop_entry, long_separator_loop;
3344
3345 ASSERT(args->length() == 2);
3346 VisitForStackValue(args->at(1));
3347 VisitForAccumulatorValue(args->at(0));
3348
3349 // All aliases of the same register have disjoint lifetimes.
3350 Register array = r0;
3351 Register elements = no_reg; // Will be r0.
3352 Register result = no_reg; // Will be r0.
3353 Register separator = r1;
3354 Register array_length = r2;
3355 Register result_pos = no_reg; // Will be r2
3356 Register string_length = r3;
3357 Register string = r4;
3358 Register element = r5;
3359 Register elements_end = r6;
3360 Register scratch1 = r7;
3361 Register scratch2 = r9;
3362
3363 // Separator operand is on the stack.
3364 __ pop(separator);
3365
3366 // Check that the array is a JSArray.
3367 __ JumpIfSmi(array, &bailout);
3368 __ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE);
3369 __ b(ne, &bailout);
3370
3371 // Check that the array has fast elements.
3372 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset));
3373 __ tst(scratch2, Operand(1 << Map::kHasFastElements));
3374 __ b(eq, &bailout);
3375
3376 // If the array has length zero, return the empty string.
3377 __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset));
3378 __ SmiUntag(array_length, SetCC);
3379 __ b(ne, &non_trivial_array);
3380 __ LoadRoot(r0, Heap::kEmptyStringRootIndex);
3381 __ b(&done);
3382
3383 __ bind(&non_trivial_array);
3384
3385 // Get the FixedArray containing array's elements.
3386 elements = array;
3387 __ ldr(elements, FieldMemOperand(array, JSArray::kElementsOffset));
3388 array = no_reg; // End of array's live range.
3389
3390 // Check that all array elements are sequential ASCII strings, and
3391 // accumulate the sum of their lengths, as a smi-encoded value.
3392 __ mov(string_length, Operand(0));
3393 __ add(element,
3394 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3395 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
3396 // Loop condition: while (element < elements_end).
3397 // Live values in registers:
3398 // elements: Fixed array of strings.
3399 // array_length: Length of the fixed array of strings (not smi)
3400 // separator: Separator string
3401 // string_length: Accumulated sum of string lengths (smi).
3402 // element: Current array element.
3403 // elements_end: Array end.
3404 if (FLAG_debug_code) {
3405 __ cmp(array_length, Operand(0));
3406 __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin");
3407 }
3408 __ bind(&loop);
3409 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3410 __ JumpIfSmi(string, &bailout);
3411 __ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset));
3412 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
3413 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
3414 __ ldr(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset));
3415 __ add(string_length, string_length, Operand(scratch1));
3416 __ b(vs, &bailout);
3417 __ cmp(element, elements_end);
3418 __ b(lt, &loop);
3419
3420 // If array_length is 1, return elements[0], a string.
3421 __ cmp(array_length, Operand(1));
3422 __ b(ne, &not_size_one_array);
3423 __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize));
3424 __ b(&done);
3425
3426 __ bind(&not_size_one_array);
3427
3428 // Live values in registers:
3429 // separator: Separator string
3430 // array_length: Length of the array.
3431 // string_length: Sum of string lengths (smi).
3432 // elements: FixedArray of strings.
3433
3434 // Check that the separator is a flat ASCII string.
3435 __ JumpIfSmi(separator, &bailout);
3436 __ ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset));
3437 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
3438 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
3439
3440 // Add (separator length times array_length) - separator length to the
3441 // string_length to get the length of the result string. array_length is not
3442 // smi but the other values are, so the result is a smi
3443 __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset));
3444 __ sub(string_length, string_length, Operand(scratch1));
3445 __ smull(scratch2, ip, array_length, scratch1);
3446 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are
3447 // zero.
3448 __ cmp(ip, Operand(0));
3449 __ b(ne, &bailout);
3450 __ tst(scratch2, Operand(0x80000000));
3451 __ b(ne, &bailout);
3452 __ add(string_length, string_length, Operand(scratch2));
3453 __ b(vs, &bailout);
3454 __ SmiUntag(string_length);
3455
3456 // Get first element in the array to free up the elements register to be used
3457 // for the result.
3458 __ add(element,
3459 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3460 result = elements; // End of live range for elements.
3461 elements = no_reg;
3462 // Live values in registers:
3463 // element: First array element
3464 // separator: Separator string
3465 // string_length: Length of result string (not smi)
3466 // array_length: Length of the array.
3467 __ AllocateAsciiString(result,
3468 string_length,
3469 scratch1,
3470 scratch2,
3471 elements_end,
3472 &bailout);
3473 // Prepare for looping. Set up elements_end to end of the array. Set
3474 // result_pos to the position of the result where to write the first
3475 // character.
3476 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
3477 result_pos = array_length; // End of live range for array_length.
3478 array_length = no_reg;
3479 __ add(result_pos,
3480 result,
3481 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3482
3483 // Check the length of the separator.
3484 __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset));
3485 __ cmp(scratch1, Operand(Smi::FromInt(1)));
3486 __ b(eq, &one_char_separator);
3487 __ b(gt, &long_separator);
3488
3489 // Empty separator case
3490 __ bind(&empty_separator_loop);
3491 // Live values in registers:
3492 // result_pos: the position to which we are currently copying characters.
3493 // element: Current array element.
3494 // elements_end: Array end.
3495
3496 // Copy next array element to the result.
3497 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3498 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
3499 __ SmiUntag(string_length);
3500 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3501 __ CopyBytes(string, result_pos, string_length, scratch1);
3502 __ cmp(element, elements_end);
3503 __ b(lt, &empty_separator_loop); // End while (element < elements_end).
3504 ASSERT(result.is(r0));
3505 __ b(&done);
3506
3507 // One-character separator case
3508 __ bind(&one_char_separator);
3509 // Replace separator with its ascii character value.
3510 __ ldrb(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize));
3511 // Jump into the loop after the code that copies the separator, so the first
3512 // element is not preceded by a separator
3513 __ jmp(&one_char_separator_loop_entry);
3514
3515 __ bind(&one_char_separator_loop);
3516 // Live values in registers:
3517 // result_pos: the position to which we are currently copying characters.
3518 // element: Current array element.
3519 // elements_end: Array end.
3520 // separator: Single separator ascii char (in lower byte).
3521
3522 // Copy the separator character to the result.
3523 __ strb(separator, MemOperand(result_pos, 1, PostIndex));
3524
3525 // Copy next array element to the result.
3526 __ bind(&one_char_separator_loop_entry);
3527 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3528 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
3529 __ SmiUntag(string_length);
3530 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3531 __ CopyBytes(string, result_pos, string_length, scratch1);
3532 __ cmp(element, elements_end);
3533 __ b(lt, &one_char_separator_loop); // End while (element < elements_end).
3534 ASSERT(result.is(r0));
3535 __ b(&done);
3536
3537 // Long separator case (separator is more than one character). Entry is at the
3538 // label long_separator below.
3539 __ bind(&long_separator_loop);
3540 // Live values in registers:
3541 // result_pos: the position to which we are currently copying characters.
3542 // element: Current array element.
3543 // elements_end: Array end.
3544 // separator: Separator string.
3545
3546 // Copy the separator to the result.
3547 __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset));
3548 __ SmiUntag(string_length);
3549 __ add(string,
3550 separator,
3551 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3552 __ CopyBytes(string, result_pos, string_length, scratch1);
3553
3554 __ bind(&long_separator);
3555 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3556 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
3557 __ SmiUntag(string_length);
3558 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3559 __ CopyBytes(string, result_pos, string_length, scratch1);
3560 __ cmp(element, elements_end);
3561 __ b(lt, &long_separator_loop); // End while (element < elements_end).
3562 ASSERT(result.is(r0));
3563 __ b(&done);
3564
3565 __ bind(&bailout);
3020 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); 3566 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
3567 __ bind(&done);
3021 context()->Plug(r0); 3568 context()->Plug(r0);
3022 return;
3023 } 3569 }
3024 3570
3025 3571
3026 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { 3572 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
3027 Handle<String> name = expr->name(); 3573 Handle<String> name = expr->name();
3028 if (name->length() > 0 && name->Get(0) == '_') { 3574 if (name->length() > 0 && name->Get(0) == '_') {
3029 Comment cmnt(masm_, "[ InlineRuntimeCall"); 3575 Comment cmnt(masm_, "[ InlineRuntimeCall");
3030 EmitInlineRuntimeCall(expr); 3576 EmitInlineRuntimeCall(expr);
3031 return; 3577 return;
3032 } 3578 }
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
3077 } else { 3623 } else {
3078 VisitForStackValue(prop->obj()); 3624 VisitForStackValue(prop->obj());
3079 VisitForStackValue(prop->key()); 3625 VisitForStackValue(prop->key());
3080 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag()))); 3626 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
3081 __ push(r1); 3627 __ push(r1);
3082 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); 3628 __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
3083 context()->Plug(r0); 3629 context()->Plug(r0);
3084 } 3630 }
3085 } else if (var != NULL) { 3631 } else if (var != NULL) {
3086 // Delete of an unqualified identifier is disallowed in strict mode 3632 // Delete of an unqualified identifier is disallowed in strict mode
3087 // so this code can only be reached in non-strict mode. 3633 // but "delete this" is.
3088 ASSERT(strict_mode_flag() == kNonStrictMode); 3634 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
3089 if (var->is_global()) { 3635 if (var->is_global()) {
3090 __ ldr(r2, GlobalObjectOperand()); 3636 __ ldr(r2, GlobalObjectOperand());
3091 __ mov(r1, Operand(var->name())); 3637 __ mov(r1, Operand(var->name()));
3092 __ mov(r0, Operand(Smi::FromInt(kNonStrictMode))); 3638 __ mov(r0, Operand(Smi::FromInt(kNonStrictMode)));
3093 __ Push(r2, r1, r0); 3639 __ Push(r2, r1, r0);
3094 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); 3640 __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
3095 context()->Plug(r0); 3641 context()->Plug(r0);
3096 } else if (var->AsSlot() != NULL && 3642 } else if (var->AsSlot() != NULL &&
3097 var->AsSlot()->type() != Slot::LOOKUP) { 3643 var->AsSlot()->type() != Slot::LOOKUP) {
3098 // Result of deleting non-global, non-dynamic variables is false. 3644 // Result of deleting non-global, non-dynamic variables is false.
(...skipping 19 matching lines...) Expand all
3118 3664
3119 case Token::VOID: { 3665 case Token::VOID: {
3120 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 3666 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3121 VisitForEffect(expr->expression()); 3667 VisitForEffect(expr->expression());
3122 context()->Plug(Heap::kUndefinedValueRootIndex); 3668 context()->Plug(Heap::kUndefinedValueRootIndex);
3123 break; 3669 break;
3124 } 3670 }
3125 3671
3126 case Token::NOT: { 3672 case Token::NOT: {
3127 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 3673 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
3128 Label materialize_true, materialize_false; 3674 if (context()->IsEffect()) {
3129 Label* if_true = NULL; 3675 // Unary NOT has no side effects so it's only necessary to visit the
3130 Label* if_false = NULL; 3676 // subexpression. Match the optimizing compiler by not branching.
3131 Label* fall_through = NULL; 3677 VisitForEffect(expr->expression());
3678 } else {
3679 Label materialize_true, materialize_false;
3680 Label* if_true = NULL;
3681 Label* if_false = NULL;
3682 Label* fall_through = NULL;
3132 3683
3133 // Notice that the labels are swapped. 3684 // Notice that the labels are swapped.
3134 context()->PrepareTest(&materialize_true, &materialize_false, 3685 context()->PrepareTest(&materialize_true, &materialize_false,
3135 &if_false, &if_true, &fall_through); 3686 &if_false, &if_true, &fall_through);
3136 if (context()->IsTest()) ForwardBailoutToChild(expr); 3687 if (context()->IsTest()) ForwardBailoutToChild(expr);
3137 VisitForControl(expr->expression(), if_true, if_false, fall_through); 3688 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3138 context()->Plug(if_false, if_true); // Labels swapped. 3689 context()->Plug(if_false, if_true); // Labels swapped.
3690 }
3139 break; 3691 break;
3140 } 3692 }
3141 3693
3142 case Token::TYPEOF: { 3694 case Token::TYPEOF: {
3143 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 3695 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
3144 { StackValueContext context(this); 3696 { StackValueContext context(this);
3145 VisitForTypeofValue(expr->expression()); 3697 VisitForTypeofValue(expr->expression());
3146 } 3698 }
3147 __ CallRuntime(Runtime::kTypeof, 1); 3699 __ CallRuntime(Runtime::kTypeof, 1);
3148 context()->Plug(r0); 3700 context()->Plug(r0);
(...skipping 11 matching lines...) Expand all
3160 __ bind(&no_conversion); 3712 __ bind(&no_conversion);
3161 context()->Plug(result_register()); 3713 context()->Plug(result_register());
3162 break; 3714 break;
3163 } 3715 }
3164 3716
3165 case Token::SUB: { 3717 case Token::SUB: {
3166 Comment cmt(masm_, "[ UnaryOperation (SUB)"); 3718 Comment cmt(masm_, "[ UnaryOperation (SUB)");
3167 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); 3719 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3168 UnaryOverwriteMode overwrite = 3720 UnaryOverwriteMode overwrite =
3169 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; 3721 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
3170 GenericUnaryOpStub stub(Token::SUB, 3722 GenericUnaryOpStub stub(Token::SUB, overwrite, NO_UNARY_FLAGS);
3171 overwrite,
3172 NO_UNARY_FLAGS);
3173 // GenericUnaryOpStub expects the argument to be in the 3723 // GenericUnaryOpStub expects the argument to be in the
3174 // accumulator register r0. 3724 // accumulator register r0.
3175 VisitForAccumulatorValue(expr->expression()); 3725 VisitForAccumulatorValue(expr->expression());
3176 __ CallStub(&stub); 3726 __ CallStub(&stub);
3177 context()->Plug(r0); 3727 context()->Plug(r0);
3178 break; 3728 break;
3179 } 3729 }
3180 3730
3181 case Token::BIT_NOT: { 3731 case Token::BIT_NOT: {
3182 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)"); 3732 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
3295 case KEYED_PROPERTY: 3845 case KEYED_PROPERTY:
3296 __ str(r0, MemOperand(sp, 2 * kPointerSize)); 3846 __ str(r0, MemOperand(sp, 2 * kPointerSize));
3297 break; 3847 break;
3298 } 3848 }
3299 } 3849 }
3300 } 3850 }
3301 3851
3302 3852
3303 // Inline smi case if we are in a loop. 3853 // Inline smi case if we are in a loop.
3304 Label stub_call, done; 3854 Label stub_call, done;
3855 JumpPatchSite patch_site(masm_);
3856
3305 int count_value = expr->op() == Token::INC ? 1 : -1; 3857 int count_value = expr->op() == Token::INC ? 1 : -1;
3306 if (ShouldInlineSmiCase(expr->op())) { 3858 if (ShouldInlineSmiCase(expr->op())) {
3307 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC); 3859 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
3308 __ b(vs, &stub_call); 3860 __ b(vs, &stub_call);
3309 // We could eliminate this smi check if we split the code at 3861 // We could eliminate this smi check if we split the code at
3310 // the first smi check before calling ToNumber. 3862 // the first smi check before calling ToNumber.
3311 __ JumpIfSmi(r0, &done); 3863 patch_site.EmitJumpIfSmi(r0, &done);
3864
3312 __ bind(&stub_call); 3865 __ bind(&stub_call);
3313 // Call stub. Undo operation first. 3866 // Call stub. Undo operation first.
3314 __ sub(r0, r0, Operand(Smi::FromInt(count_value))); 3867 __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
3315 } 3868 }
3316 __ mov(r1, Operand(Smi::FromInt(count_value))); 3869 __ mov(r1, Operand(Smi::FromInt(count_value)));
3317 3870
3318 // Record position before stub call. 3871 // Record position before stub call.
3319 SetSourcePosition(expr->position()); 3872 SetSourcePosition(expr->position());
3320 3873
3321 GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE, r1, r0); 3874 TypeRecordingBinaryOpStub stub(Token::ADD, NO_OVERWRITE);
3322 __ CallStub(&stub); 3875 EmitCallIC(stub.GetCode(), &patch_site);
3323 __ bind(&done); 3876 __ bind(&done);
3324 3877
3325 // Store the value returned in r0. 3878 // Store the value returned in r0.
3326 switch (assign_type) { 3879 switch (assign_type) {
3327 case VARIABLE: 3880 case VARIABLE:
3328 if (expr->is_postfix()) { 3881 if (expr->is_postfix()) {
3329 { EffectContext context(this); 3882 { EffectContext context(this);
3330 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 3883 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3331 Token::ASSIGN); 3884 Token::ASSIGN);
3332 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3885 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3333 context.Plug(r0); 3886 context.Plug(r0);
3334 } 3887 }
3335 // For all contexts except EffectConstant We have the result on 3888 // For all contexts except EffectConstant We have the result on
3336 // top of the stack. 3889 // top of the stack.
3337 if (!context()->IsEffect()) { 3890 if (!context()->IsEffect()) {
3338 context()->PlugTOS(); 3891 context()->PlugTOS();
3339 } 3892 }
3340 } else { 3893 } else {
3341 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 3894 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3342 Token::ASSIGN); 3895 Token::ASSIGN);
3343 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3896 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3344 context()->Plug(r0); 3897 context()->Plug(r0);
3345 } 3898 }
3346 break; 3899 break;
3347 case NAMED_PROPERTY: { 3900 case NAMED_PROPERTY: {
3348 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); 3901 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
3349 __ pop(r1); 3902 __ pop(r1);
3350 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 3903 Handle<Code> ic(Builtins::builtin(
3904 is_strict_mode() ? Builtins::StoreIC_Initialize_Strict
3905 : Builtins::StoreIC_Initialize));
3351 EmitCallIC(ic, RelocInfo::CODE_TARGET); 3906 EmitCallIC(ic, RelocInfo::CODE_TARGET);
3352 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3907 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3353 if (expr->is_postfix()) { 3908 if (expr->is_postfix()) {
3354 if (!context()->IsEffect()) { 3909 if (!context()->IsEffect()) {
3355 context()->PlugTOS(); 3910 context()->PlugTOS();
3356 } 3911 }
3357 } else { 3912 } else {
3358 context()->Plug(r0); 3913 context()->Plug(r0);
3359 } 3914 }
3360 break; 3915 break;
3361 } 3916 }
3362 case KEYED_PROPERTY: { 3917 case KEYED_PROPERTY: {
3363 __ pop(r1); // Key. 3918 __ pop(r1); // Key.
3364 __ pop(r2); // Receiver. 3919 __ pop(r2); // Receiver.
3365 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 3920 Handle<Code> ic(Builtins::builtin(
3921 is_strict_mode() ? Builtins::KeyedStoreIC_Initialize_Strict
3922 : Builtins::KeyedStoreIC_Initialize));
3366 EmitCallIC(ic, RelocInfo::CODE_TARGET); 3923 EmitCallIC(ic, RelocInfo::CODE_TARGET);
3367 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3924 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3368 if (expr->is_postfix()) { 3925 if (expr->is_postfix()) {
3369 if (!context()->IsEffect()) { 3926 if (!context()->IsEffect()) {
3370 context()->PlugTOS(); 3927 context()->PlugTOS();
3371 } 3928 }
3372 } else { 3929 } else {
3373 context()->Plug(r0); 3930 context()->Plug(r0);
3374 } 3931 }
3375 break; 3932 break;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
3433 UnaryOperation* left_unary = left->AsUnaryOperation(); 3990 UnaryOperation* left_unary = left->AsUnaryOperation();
3434 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false; 3991 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
3435 Handle<String> check = Handle<String>::cast(right_literal_value); 3992 Handle<String> check = Handle<String>::cast(right_literal_value);
3436 3993
3437 { AccumulatorValueContext context(this); 3994 { AccumulatorValueContext context(this);
3438 VisitForTypeofValue(left_unary->expression()); 3995 VisitForTypeofValue(left_unary->expression());
3439 } 3996 }
3440 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); 3997 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3441 3998
3442 if (check->Equals(Heap::number_symbol())) { 3999 if (check->Equals(Heap::number_symbol())) {
3443 __ tst(r0, Operand(kSmiTagMask)); 4000 __ JumpIfSmi(r0, if_true);
3444 __ b(eq, if_true);
3445 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); 4001 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
3446 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); 4002 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
3447 __ cmp(r0, ip); 4003 __ cmp(r0, ip);
3448 Split(eq, if_true, if_false, fall_through); 4004 Split(eq, if_true, if_false, fall_through);
3449 } else if (check->Equals(Heap::string_symbol())) { 4005 } else if (check->Equals(Heap::string_symbol())) {
3450 __ tst(r0, Operand(kSmiTagMask)); 4006 __ JumpIfSmi(r0, if_false);
3451 __ b(eq, if_false);
3452 // Check for undetectable objects => false. 4007 // Check for undetectable objects => false.
3453 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); 4008 __ CompareObjectType(r0, r0, r1, FIRST_NONSTRING_TYPE);
4009 __ b(ge, if_false);
3454 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); 4010 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
3455 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); 4011 __ tst(r1, Operand(1 << Map::kIsUndetectable));
3456 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); 4012 Split(eq, if_true, if_false, fall_through);
3457 __ b(eq, if_false);
3458 __ ldrb(r1, FieldMemOperand(r0, Map::kInstanceTypeOffset));
3459 __ cmp(r1, Operand(FIRST_NONSTRING_TYPE));
3460 Split(lt, if_true, if_false, fall_through);
3461 } else if (check->Equals(Heap::boolean_symbol())) { 4013 } else if (check->Equals(Heap::boolean_symbol())) {
3462 __ LoadRoot(ip, Heap::kTrueValueRootIndex); 4014 __ CompareRoot(r0, Heap::kTrueValueRootIndex);
3463 __ cmp(r0, ip);
3464 __ b(eq, if_true); 4015 __ b(eq, if_true);
3465 __ LoadRoot(ip, Heap::kFalseValueRootIndex); 4016 __ CompareRoot(r0, Heap::kFalseValueRootIndex);
3466 __ cmp(r0, ip);
3467 Split(eq, if_true, if_false, fall_through); 4017 Split(eq, if_true, if_false, fall_through);
3468 } else if (check->Equals(Heap::undefined_symbol())) { 4018 } else if (check->Equals(Heap::undefined_symbol())) {
3469 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 4019 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
3470 __ cmp(r0, ip);
3471 __ b(eq, if_true); 4020 __ b(eq, if_true);
3472 __ tst(r0, Operand(kSmiTagMask)); 4021 __ JumpIfSmi(r0, if_false);
3473 __ b(eq, if_false);
3474 // Check for undetectable objects => true. 4022 // Check for undetectable objects => true.
3475 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); 4023 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
3476 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset)); 4024 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
3477 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); 4025 __ tst(r1, Operand(1 << Map::kIsUndetectable));
3478 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); 4026 Split(ne, if_true, if_false, fall_through);
4027
4028 } else if (check->Equals(Heap::function_symbol())) {
4029 __ JumpIfSmi(r0, if_false);
4030 __ CompareObjectType(r0, r1, r0, FIRST_FUNCTION_CLASS_TYPE);
4031 Split(ge, if_true, if_false, fall_through);
4032
4033 } else if (check->Equals(Heap::object_symbol())) {
4034 __ JumpIfSmi(r0, if_false);
4035 __ CompareRoot(r0, Heap::kNullValueRootIndex);
4036 __ b(eq, if_true);
4037 // Check for JS objects => true.
4038 __ CompareObjectType(r0, r0, r1, FIRST_JS_OBJECT_TYPE);
4039 __ b(lo, if_false);
4040 __ CompareInstanceType(r0, r1, FIRST_FUNCTION_CLASS_TYPE);
4041 __ b(hs, if_false);
4042 // Check for undetectable objects => false.
4043 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
4044 __ tst(r1, Operand(1 << Map::kIsUndetectable));
3479 Split(eq, if_true, if_false, fall_through); 4045 Split(eq, if_true, if_false, fall_through);
3480 } else if (check->Equals(Heap::function_symbol())) {
3481 __ tst(r0, Operand(kSmiTagMask));
3482 __ b(eq, if_false);
3483 __ CompareObjectType(r0, r1, r0, JS_FUNCTION_TYPE);
3484 __ b(eq, if_true);
3485 // Regular expressions => 'function' (they are callable).
3486 __ CompareInstanceType(r1, r0, JS_REGEXP_TYPE);
3487 Split(eq, if_true, if_false, fall_through);
3488 } else if (check->Equals(Heap::object_symbol())) {
3489 __ tst(r0, Operand(kSmiTagMask));
3490 __ b(eq, if_false);
3491 __ LoadRoot(ip, Heap::kNullValueRootIndex);
3492 __ cmp(r0, ip);
3493 __ b(eq, if_true);
3494 // Regular expressions => 'function', not 'object'.
3495 __ CompareObjectType(r0, r1, r0, JS_REGEXP_TYPE);
3496 __ b(eq, if_false);
3497 // Check for undetectable objects => false.
3498 __ ldrb(r0, FieldMemOperand(r1, Map::kBitFieldOffset));
3499 __ and_(r0, r0, Operand(1 << Map::kIsUndetectable));
3500 __ cmp(r0, Operand(1 << Map::kIsUndetectable));
3501 __ b(eq, if_false);
3502 // Check for JS objects => true.
3503 __ ldrb(r0, FieldMemOperand(r1, Map::kInstanceTypeOffset));
3504 __ cmp(r0, Operand(FIRST_JS_OBJECT_TYPE));
3505 __ b(lt, if_false);
3506 __ cmp(r0, Operand(LAST_JS_OBJECT_TYPE));
3507 Split(le, if_true, if_false, fall_through);
3508 } else { 4046 } else {
3509 if (if_false != fall_through) __ jmp(if_false); 4047 if (if_false != fall_through) __ jmp(if_false);
3510 } 4048 }
3511 4049
3512 return true; 4050 return true;
3513 } 4051 }
3514 4052
3515 4053
3516 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 4054 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3517 Comment cmnt(masm_, "[ CompareOperation"); 4055 Comment cmnt(masm_, "[ CompareOperation");
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
3669 4207
3670 4208
3671 Register FullCodeGenerator::context_register() { 4209 Register FullCodeGenerator::context_register() {
3672 return cp; 4210 return cp;
3673 } 4211 }
3674 4212
3675 4213
3676 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) { 4214 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
3677 ASSERT(mode == RelocInfo::CODE_TARGET || 4215 ASSERT(mode == RelocInfo::CODE_TARGET ||
3678 mode == RelocInfo::CODE_TARGET_CONTEXT); 4216 mode == RelocInfo::CODE_TARGET_CONTEXT);
4217 switch (ic->kind()) {
4218 case Code::LOAD_IC:
4219 __ IncrementCounter(&Counters::named_load_full, 1, r1, r2);
4220 break;
4221 case Code::KEYED_LOAD_IC:
4222 __ IncrementCounter(&Counters::keyed_load_full, 1, r1, r2);
4223 break;
4224 case Code::STORE_IC:
4225 __ IncrementCounter(&Counters::named_store_full, 1, r1, r2);
4226 break;
4227 case Code::KEYED_STORE_IC:
4228 __ IncrementCounter(&Counters::keyed_store_full, 1, r1, r2);
4229 default:
4230 break;
4231 }
4232
3679 __ Call(ic, mode); 4233 __ Call(ic, mode);
3680 } 4234 }
3681 4235
3682 4236
3683 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) { 4237 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
4238 switch (ic->kind()) {
4239 case Code::LOAD_IC:
4240 __ IncrementCounter(&Counters::named_load_full, 1, r1, r2);
4241 break;
4242 case Code::KEYED_LOAD_IC:
4243 __ IncrementCounter(&Counters::keyed_load_full, 1, r1, r2);
4244 break;
4245 case Code::STORE_IC:
4246 __ IncrementCounter(&Counters::named_store_full, 1, r1, r2);
4247 break;
4248 case Code::KEYED_STORE_IC:
4249 __ IncrementCounter(&Counters::keyed_store_full, 1, r1, r2);
4250 default:
4251 break;
4252 }
4253
3684 __ Call(ic, RelocInfo::CODE_TARGET); 4254 __ Call(ic, RelocInfo::CODE_TARGET);
3685 if (patch_site != NULL && patch_site->is_bound()) { 4255 if (patch_site != NULL && patch_site->is_bound()) {
3686 patch_site->EmitPatchInfo(); 4256 patch_site->EmitPatchInfo();
3687 } else { 4257 } else {
3688 __ nop(); // Signals no inlined code. 4258 __ nop(); // Signals no inlined code.
3689 } 4259 }
3690 } 4260 }
3691 4261
3692 4262
3693 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { 4263 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
3727 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. 4297 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value.
3728 __ add(pc, r1, Operand(masm_->CodeObject())); 4298 __ add(pc, r1, Operand(masm_->CodeObject()));
3729 } 4299 }
3730 4300
3731 4301
3732 #undef __ 4302 #undef __
3733 4303
3734 } } // namespace v8::internal 4304 } } // namespace v8::internal
3735 4305
3736 #endif // V8_TARGET_ARCH_ARM 4306 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « src/arm/disasm-arm.cc ('k') | src/arm/ic-arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698