OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
271 Comment cmnt(masm_, "[ Declarations"); | 271 Comment cmnt(masm_, "[ Declarations"); |
272 scope()->VisitIllegalRedeclaration(this); | 272 scope()->VisitIllegalRedeclaration(this); |
273 | 273 |
274 } else { | 274 } else { |
275 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); | 275 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS); |
276 { Comment cmnt(masm_, "[ Declarations"); | 276 { Comment cmnt(masm_, "[ Declarations"); |
277 // For named function expressions, declare the function name as a | 277 // For named function expressions, declare the function name as a |
278 // constant. | 278 // constant. |
279 if (scope()->is_function_scope() && scope()->function() != NULL) { | 279 if (scope()->is_function_scope() && scope()->function() != NULL) { |
280 int ignored = 0; | 280 int ignored = 0; |
281 EmitDeclaration(scope()->function(), Variable::CONST, NULL, &ignored); | 281 EmitDeclaration(scope()->function(), CONST, NULL, &ignored); |
282 } | 282 } |
283 VisitDeclarations(scope()->declarations()); | 283 VisitDeclarations(scope()->declarations()); |
284 } | 284 } |
285 | 285 |
286 { Comment cmnt(masm_, "[ Stack check"); | 286 { Comment cmnt(masm_, "[ Stack check"); |
287 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); | 287 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS); |
288 Label ok; | 288 Label ok; |
289 __ LoadRoot(t0, Heap::kStackLimitRootIndex); | 289 __ LoadRoot(t0, Heap::kStackLimitRootIndex); |
290 __ Branch(&ok, hs, sp, Operand(t0)); | 290 __ Branch(&ok, hs, sp, Operand(t0)); |
291 StackCheckStub stub; | 291 StackCheckStub stub; |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
714 | 714 |
715 if (should_normalize) { | 715 if (should_normalize) { |
716 __ LoadRoot(t0, Heap::kTrueValueRootIndex); | 716 __ LoadRoot(t0, Heap::kTrueValueRootIndex); |
717 Split(eq, a0, Operand(t0), if_true, if_false, NULL); | 717 Split(eq, a0, Operand(t0), if_true, if_false, NULL); |
718 __ bind(&skip); | 718 __ bind(&skip); |
719 } | 719 } |
720 } | 720 } |
721 | 721 |
722 | 722 |
723 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, | 723 void FullCodeGenerator::EmitDeclaration(VariableProxy* proxy, |
724 Variable::Mode mode, | 724 VariableMode mode, |
725 FunctionLiteral* function, | 725 FunctionLiteral* function, |
726 int* global_count) { | 726 int* global_count) { |
727 // If it was not possible to allocate the variable at compile time, we | 727 // If it was not possible to allocate the variable at compile time, we |
728 // need to "declare" it at runtime to make sure it actually exists in the | 728 // need to "declare" it at runtime to make sure it actually exists in the |
729 // local context. | 729 // local context. |
730 Variable* variable = proxy->var(); | 730 Variable* variable = proxy->var(); |
731 switch (variable->location()) { | 731 switch (variable->location()) { |
732 case Variable::UNALLOCATED: | 732 case Variable::UNALLOCATED: |
733 ++(*global_count); | 733 ++(*global_count); |
734 break; | 734 break; |
735 | 735 |
736 case Variable::PARAMETER: | 736 case Variable::PARAMETER: |
737 case Variable::LOCAL: | 737 case Variable::LOCAL: |
738 if (function != NULL) { | 738 if (function != NULL) { |
739 Comment cmnt(masm_, "[ Declaration"); | 739 Comment cmnt(masm_, "[ Declaration"); |
740 VisitForAccumulatorValue(function); | 740 VisitForAccumulatorValue(function); |
741 __ sw(result_register(), StackOperand(variable)); | 741 __ sw(result_register(), StackOperand(variable)); |
742 } else if (mode == Variable::CONST || mode == Variable::LET) { | 742 } else if (mode == CONST || mode == LET) { |
743 Comment cmnt(masm_, "[ Declaration"); | 743 Comment cmnt(masm_, "[ Declaration"); |
744 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 744 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
745 __ sw(t0, StackOperand(variable)); | 745 __ sw(t0, StackOperand(variable)); |
746 } | 746 } |
747 break; | 747 break; |
748 | 748 |
749 case Variable::CONTEXT: | 749 case Variable::CONTEXT: |
750 // The variable in the decl always resides in the current function | 750 // The variable in the decl always resides in the current function |
751 // context. | 751 // context. |
752 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); | 752 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); |
(...skipping 15 matching lines...) Expand all Loading... |
768 // We know that we have written a function, which is not a smi. | 768 // We know that we have written a function, which is not a smi. |
769 __ RecordWriteContextSlot(cp, | 769 __ RecordWriteContextSlot(cp, |
770 offset, | 770 offset, |
771 result_register(), | 771 result_register(), |
772 a2, | 772 a2, |
773 kRAHasBeenSaved, | 773 kRAHasBeenSaved, |
774 kDontSaveFPRegs, | 774 kDontSaveFPRegs, |
775 EMIT_REMEMBERED_SET, | 775 EMIT_REMEMBERED_SET, |
776 OMIT_SMI_CHECK); | 776 OMIT_SMI_CHECK); |
777 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 777 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
778 } else if (mode == Variable::CONST || mode == Variable::LET) { | 778 } else if (mode == CONST || mode == LET) { |
779 Comment cmnt(masm_, "[ Declaration"); | 779 Comment cmnt(masm_, "[ Declaration"); |
780 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 780 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
781 __ sw(at, ContextOperand(cp, variable->index())); | 781 __ sw(at, ContextOperand(cp, variable->index())); |
782 // No write barrier since the_hole_value is in old space. | 782 // No write barrier since the_hole_value is in old space. |
783 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); | 783 PrepareForBailoutForId(proxy->id(), NO_REGISTERS); |
784 } | 784 } |
785 break; | 785 break; |
786 | 786 |
787 case Variable::LOOKUP: { | 787 case Variable::LOOKUP: { |
788 Comment cmnt(masm_, "[ Declaration"); | 788 Comment cmnt(masm_, "[ Declaration"); |
789 __ li(a2, Operand(variable->name())); | 789 __ li(a2, Operand(variable->name())); |
790 // Declaration nodes are always introduced in one of three modes. | 790 // Declaration nodes are always introduced in one of three modes. |
791 ASSERT(mode == Variable::VAR || | 791 ASSERT(mode == VAR || mode == CONST || mode == LET); |
792 mode == Variable::CONST || | 792 PropertyAttributes attr = (mode == CONST) ? READ_ONLY : NONE; |
793 mode == Variable::LET); | |
794 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE; | |
795 __ li(a1, Operand(Smi::FromInt(attr))); | 793 __ li(a1, Operand(Smi::FromInt(attr))); |
796 // Push initial value, if any. | 794 // Push initial value, if any. |
797 // Note: For variables we must not push an initial value (such as | 795 // Note: For variables we must not push an initial value (such as |
798 // 'undefined') because we may have a (legal) redeclaration and we | 796 // 'undefined') because we may have a (legal) redeclaration and we |
799 // must not destroy the current value. | 797 // must not destroy the current value. |
800 if (function != NULL) { | 798 if (function != NULL) { |
801 __ Push(cp, a2, a1); | 799 __ Push(cp, a2, a1); |
802 // Push initial value for function declaration. | 800 // Push initial value for function declaration. |
803 VisitForStackValue(function); | 801 VisitForStackValue(function); |
804 } else if (mode == Variable::CONST || mode == Variable::LET) { | 802 } else if (mode == CONST || mode == LET) { |
805 __ LoadRoot(a0, Heap::kTheHoleValueRootIndex); | 803 __ LoadRoot(a0, Heap::kTheHoleValueRootIndex); |
806 __ Push(cp, a2, a1, a0); | 804 __ Push(cp, a2, a1, a0); |
807 } else { | 805 } else { |
808 ASSERT(Smi::FromInt(0) == 0); | 806 ASSERT(Smi::FromInt(0) == 0); |
809 __ mov(a0, zero_reg); // Smi::FromInt(0) indicates no initial value. | 807 __ mov(a0, zero_reg); // Smi::FromInt(0) indicates no initial value. |
810 __ Push(cp, a2, a1, a0); | 808 __ Push(cp, a2, a1, a0); |
811 } | 809 } |
812 __ CallRuntime(Runtime::kDeclareContextSlot, 4); | 810 __ CallRuntime(Runtime::kDeclareContextSlot, 4); |
813 break; | 811 break; |
814 } | 812 } |
(...skipping 401 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1216 | 1214 |
1217 void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, | 1215 void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var, |
1218 TypeofState typeof_state, | 1216 TypeofState typeof_state, |
1219 Label* slow, | 1217 Label* slow, |
1220 Label* done) { | 1218 Label* done) { |
1221 // Generate fast-case code for variables that might be shadowed by | 1219 // Generate fast-case code for variables that might be shadowed by |
1222 // eval-introduced variables. Eval is used a lot without | 1220 // eval-introduced variables. Eval is used a lot without |
1223 // introducing variables. In those cases, we do not want to | 1221 // introducing variables. In those cases, we do not want to |
1224 // perform a runtime call for all variables in the scope | 1222 // perform a runtime call for all variables in the scope |
1225 // containing the eval. | 1223 // containing the eval. |
1226 if (var->mode() == Variable::DYNAMIC_GLOBAL) { | 1224 if (var->mode() == DYNAMIC_GLOBAL) { |
1227 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); | 1225 EmitLoadGlobalCheckExtensions(var, typeof_state, slow); |
1228 __ Branch(done); | 1226 __ Branch(done); |
1229 } else if (var->mode() == Variable::DYNAMIC_LOCAL) { | 1227 } else if (var->mode() == DYNAMIC_LOCAL) { |
1230 Variable* local = var->local_if_not_shadowed(); | 1228 Variable* local = var->local_if_not_shadowed(); |
1231 __ lw(v0, ContextSlotOperandCheckExtensions(local, slow)); | 1229 __ lw(v0, ContextSlotOperandCheckExtensions(local, slow)); |
1232 if (local->mode() == Variable::CONST) { | 1230 if (local->mode() == CONST || |
| 1231 local->mode() == LET) { |
1233 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 1232 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
1234 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. | 1233 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. |
1235 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); | 1234 if (local->mode() == CONST) { |
1236 __ movz(v0, a0, at); // Conditional move: return Undefined if TheHole. | 1235 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); |
| 1236 __ movz(v0, a0, at); // Conditional move: return Undefined if TheHole. |
| 1237 } else { // LET |
| 1238 __ Branch(done, ne, at, Operand(zero_reg)); |
| 1239 __ li(a0, Operand(var->name())); |
| 1240 __ push(a0); |
| 1241 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 1242 } |
1237 } | 1243 } |
1238 __ Branch(done); | 1244 __ Branch(done); |
1239 } | 1245 } |
1240 } | 1246 } |
1241 | 1247 |
1242 | 1248 |
1243 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1249 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
1244 // Record position before possible IC call. | 1250 // Record position before possible IC call. |
1245 SetSourcePosition(proxy->position()); | 1251 SetSourcePosition(proxy->position()); |
1246 Variable* var = proxy->var(); | 1252 Variable* var = proxy->var(); |
(...skipping 12 matching lines...) Expand all Loading... |
1259 context()->Plug(v0); | 1265 context()->Plug(v0); |
1260 break; | 1266 break; |
1261 } | 1267 } |
1262 | 1268 |
1263 case Variable::PARAMETER: | 1269 case Variable::PARAMETER: |
1264 case Variable::LOCAL: | 1270 case Variable::LOCAL: |
1265 case Variable::CONTEXT: { | 1271 case Variable::CONTEXT: { |
1266 Comment cmnt(masm_, var->IsContextSlot() | 1272 Comment cmnt(masm_, var->IsContextSlot() |
1267 ? "Context variable" | 1273 ? "Context variable" |
1268 : "Stack variable"); | 1274 : "Stack variable"); |
1269 if (var->mode() != Variable::LET && var->mode() != Variable::CONST) { | 1275 if (var->mode() != LET && var->mode() != CONST) { |
1270 context()->Plug(var); | 1276 context()->Plug(var); |
1271 } else { | 1277 } else { |
1272 // Let and const need a read barrier. | 1278 // Let and const need a read barrier. |
1273 GetVar(v0, var); | 1279 GetVar(v0, var); |
1274 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 1280 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
1275 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. | 1281 __ subu(at, v0, at); // Sub as compare: at == 0 on eq. |
1276 if (var->mode() == Variable::LET) { | 1282 if (var->mode() == LET) { |
1277 Label done; | 1283 Label done; |
1278 __ Branch(&done, ne, at, Operand(zero_reg)); | 1284 __ Branch(&done, ne, at, Operand(zero_reg)); |
1279 __ li(a0, Operand(var->name())); | 1285 __ li(a0, Operand(var->name())); |
1280 __ push(a0); | 1286 __ push(a0); |
1281 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1287 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1282 __ bind(&done); | 1288 __ bind(&done); |
1283 } else { | 1289 } else { |
1284 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); | 1290 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); |
1285 __ movz(v0, a0, at); // Conditional move: Undefined if TheHole. | 1291 __ movz(v0, a0, at); // Conditional move: Undefined if TheHole. |
1286 } | 1292 } |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1506 continue; | 1512 continue; |
1507 } | 1513 } |
1508 | 1514 |
1509 if (!result_saved) { | 1515 if (!result_saved) { |
1510 __ push(v0); | 1516 __ push(v0); |
1511 result_saved = true; | 1517 result_saved = true; |
1512 } | 1518 } |
1513 VisitForAccumulatorValue(subexpr); | 1519 VisitForAccumulatorValue(subexpr); |
1514 | 1520 |
1515 // Store the subexpression value in the array's elements. | 1521 // Store the subexpression value in the array's elements. |
1516 __ lw(a1, MemOperand(sp)); // Copy of array literal. | 1522 __ lw(t6, MemOperand(sp)); // Copy of array literal. |
1517 __ lw(a1, FieldMemOperand(a1, JSObject::kElementsOffset)); | 1523 __ lw(a1, FieldMemOperand(t6, JSObject::kElementsOffset)); |
1518 int offset = FixedArray::kHeaderSize + (i * kPointerSize); | 1524 int offset = FixedArray::kHeaderSize + (i * kPointerSize); |
1519 __ sw(result_register(), FieldMemOperand(a1, offset)); | 1525 __ sw(result_register(), FieldMemOperand(a1, offset)); |
1520 | 1526 |
| 1527 Label no_map_change; |
| 1528 __ JumpIfSmi(result_register(), &no_map_change); |
1521 // Update the write barrier for the array store with v0 as the scratch | 1529 // Update the write barrier for the array store with v0 as the scratch |
1522 // register. | 1530 // register. |
1523 __ RecordWriteField( | 1531 __ RecordWriteField( |
1524 a1, offset, result_register(), a2, kRAHasBeenSaved, kDontSaveFPRegs); | 1532 a1, offset, result_register(), a2, kRAHasBeenSaved, kDontSaveFPRegs, |
| 1533 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 1534 __ lw(a3, FieldMemOperand(a1, HeapObject::kMapOffset)); |
| 1535 __ CheckFastSmiOnlyElements(a3, a2, &no_map_change); |
| 1536 __ push(t6); // Copy of array literal. |
| 1537 __ CallRuntime(Runtime::kNonSmiElementStored, 1); |
| 1538 __ bind(&no_map_change); |
1525 | 1539 |
1526 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); | 1540 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS); |
1527 } | 1541 } |
1528 | 1542 |
1529 if (result_saved) { | 1543 if (result_saved) { |
1530 context()->PlugTOS(); | 1544 context()->PlugTOS(); |
1531 } else { | 1545 } else { |
1532 context()->Plug(v0); | 1546 context()->Plug(v0); |
1533 } | 1547 } |
1534 } | 1548 } |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1866 // scope. However, unlike var initializers, const initializers are | 1880 // scope. However, unlike var initializers, const initializers are |
1867 // able to drill a hole to that function context, even from inside a | 1881 // able to drill a hole to that function context, even from inside a |
1868 // 'with' context. We thus bypass the normal static scope lookup for | 1882 // 'with' context. We thus bypass the normal static scope lookup for |
1869 // var->IsContextSlot(). | 1883 // var->IsContextSlot(). |
1870 __ push(v0); | 1884 __ push(v0); |
1871 __ li(a0, Operand(var->name())); | 1885 __ li(a0, Operand(var->name())); |
1872 __ Push(cp, a0); // Context and name. | 1886 __ Push(cp, a0); // Context and name. |
1873 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 1887 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
1874 } | 1888 } |
1875 | 1889 |
1876 } else if (var->mode() == Variable::LET && op != Token::INIT_LET) { | 1890 } else if (var->mode() == LET && op != Token::INIT_LET) { |
1877 // Non-initializing assignment to let variable needs a write barrier. | 1891 // Non-initializing assignment to let variable needs a write barrier. |
1878 if (var->IsLookupSlot()) { | 1892 if (var->IsLookupSlot()) { |
1879 __ push(v0); // Value. | 1893 __ push(v0); // Value. |
1880 __ li(a1, Operand(var->name())); | 1894 __ li(a1, Operand(var->name())); |
1881 __ li(a0, Operand(Smi::FromInt(strict_mode_flag()))); | 1895 __ li(a0, Operand(Smi::FromInt(strict_mode_flag()))); |
1882 __ Push(cp, a1, a0); // Context, name, strict mode. | 1896 __ Push(cp, a1, a0); // Context, name, strict mode. |
1883 __ CallRuntime(Runtime::kStoreContextSlot, 4); | 1897 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
1884 } else { | 1898 } else { |
1885 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 1899 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
1886 Label assign; | 1900 Label assign; |
1887 MemOperand location = VarOperand(var, a1); | 1901 MemOperand location = VarOperand(var, a1); |
1888 __ lw(a3, location); | 1902 __ lw(a3, location); |
1889 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 1903 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
1890 __ Branch(&assign, ne, a3, Operand(t0)); | 1904 __ Branch(&assign, ne, a3, Operand(t0)); |
1891 __ li(a3, Operand(var->name())); | 1905 __ li(a3, Operand(var->name())); |
1892 __ push(a3); | 1906 __ push(a3); |
1893 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 1907 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
1894 // Perform the assignment. | 1908 // Perform the assignment. |
1895 __ bind(&assign); | 1909 __ bind(&assign); |
1896 __ sw(result_register(), location); | 1910 __ sw(result_register(), location); |
1897 if (var->IsContextSlot()) { | 1911 if (var->IsContextSlot()) { |
1898 // RecordWrite may destroy all its register arguments. | 1912 // RecordWrite may destroy all its register arguments. |
1899 __ mov(a3, result_register()); | 1913 __ mov(a3, result_register()); |
1900 int offset = Context::SlotOffset(var->index()); | 1914 int offset = Context::SlotOffset(var->index()); |
1901 __ RecordWriteContextSlot( | 1915 __ RecordWriteContextSlot( |
1902 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); | 1916 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); |
1903 } | 1917 } |
1904 } | 1918 } |
1905 | 1919 |
1906 } else if (var->mode() != Variable::CONST) { | 1920 } else if (var->mode() != CONST) { |
1907 // Assignment to var or initializing assignment to let. | 1921 // Assignment to var or initializing assignment to let. |
1908 if (var->IsStackAllocated() || var->IsContextSlot()) { | 1922 if (var->IsStackAllocated() || var->IsContextSlot()) { |
1909 MemOperand location = VarOperand(var, a1); | 1923 MemOperand location = VarOperand(var, a1); |
1910 if (FLAG_debug_code && op == Token::INIT_LET) { | 1924 if (FLAG_debug_code && op == Token::INIT_LET) { |
1911 // Check for an uninitialized let binding. | 1925 // Check for an uninitialized let binding. |
1912 __ lw(a2, location); | 1926 __ lw(a2, location); |
1913 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 1927 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
1914 __ Check(eq, "Let binding re-initialization.", a2, Operand(t0)); | 1928 __ Check(eq, "Let binding re-initialization.", a2, Operand(t0)); |
1915 } | 1929 } |
1916 // Perform the assignment. | 1930 // Perform the assignment. |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2187 for (int i = 0; i < arg_count; i++) { | 2201 for (int i = 0; i < arg_count; i++) { |
2188 VisitForStackValue(args->at(i)); | 2202 VisitForStackValue(args->at(i)); |
2189 } | 2203 } |
2190 | 2204 |
2191 // If we know that eval can only be shadowed by eval-introduced | 2205 // If we know that eval can only be shadowed by eval-introduced |
2192 // variables we attempt to load the global eval function directly | 2206 // variables we attempt to load the global eval function directly |
2193 // in generated code. If we succeed, there is no need to perform a | 2207 // in generated code. If we succeed, there is no need to perform a |
2194 // context lookup in the runtime system. | 2208 // context lookup in the runtime system. |
2195 Label done; | 2209 Label done; |
2196 Variable* var = proxy->var(); | 2210 Variable* var = proxy->var(); |
2197 if (!var->IsUnallocated() && var->mode() == Variable::DYNAMIC_GLOBAL) { | 2211 if (!var->IsUnallocated() && var->mode() == DYNAMIC_GLOBAL) { |
2198 Label slow; | 2212 Label slow; |
2199 EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow); | 2213 EmitLoadGlobalCheckExtensions(var, NOT_INSIDE_TYPEOF, &slow); |
2200 // Push the function and resolve eval. | 2214 // Push the function and resolve eval. |
2201 __ push(v0); | 2215 __ push(v0); |
2202 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); | 2216 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count); |
2203 __ jmp(&done); | 2217 __ jmp(&done); |
2204 __ bind(&slow); | 2218 __ bind(&slow); |
2205 } | 2219 } |
2206 | 2220 |
2207 // Push a copy of the function (found below the arguments) and | 2221 // Push a copy of the function (found below the arguments) and |
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2688 ASSERT(args->length() == 1); | 2702 ASSERT(args->length() == 1); |
2689 Label done, null, function, non_function_constructor; | 2703 Label done, null, function, non_function_constructor; |
2690 | 2704 |
2691 VisitForAccumulatorValue(args->at(0)); | 2705 VisitForAccumulatorValue(args->at(0)); |
2692 | 2706 |
2693 // If the object is a smi, we return null. | 2707 // If the object is a smi, we return null. |
2694 __ JumpIfSmi(v0, &null); | 2708 __ JumpIfSmi(v0, &null); |
2695 | 2709 |
2696 // Check that the object is a JS object but take special care of JS | 2710 // Check that the object is a JS object but take special care of JS |
2697 // functions to make sure they have 'Function' as their class. | 2711 // functions to make sure they have 'Function' as their class. |
| 2712 // Assume that there are only two callable types, and one of them is at |
| 2713 // either end of the type range for JS object types. Saves extra comparisons. |
| 2714 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
2698 __ GetObjectType(v0, v0, a1); // Map is now in v0. | 2715 __ GetObjectType(v0, v0, a1); // Map is now in v0. |
2699 __ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); | 2716 __ Branch(&null, lt, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); |
2700 | 2717 |
2701 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and | 2718 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == |
2702 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after | 2719 FIRST_SPEC_OBJECT_TYPE + 1); |
2703 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. | 2720 __ Branch(&function, eq, a1, Operand(FIRST_SPEC_OBJECT_TYPE)); |
2704 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); | |
2705 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == | |
2706 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); | |
2707 __ Branch(&function, ge, a1, Operand(FIRST_CALLABLE_SPEC_OBJECT_TYPE)); | |
2708 | 2721 |
2709 // Check if the constructor in the map is a function. | 2722 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == |
| 2723 LAST_SPEC_OBJECT_TYPE - 1); |
| 2724 __ Branch(&function, eq, a1, Operand(LAST_SPEC_OBJECT_TYPE)); |
| 2725 // Assume that there is no larger type. |
| 2726 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1); |
| 2727 |
| 2728 // Check if the constructor in the map is a JS function. |
2710 __ lw(v0, FieldMemOperand(v0, Map::kConstructorOffset)); | 2729 __ lw(v0, FieldMemOperand(v0, Map::kConstructorOffset)); |
2711 __ GetObjectType(v0, a1, a1); | 2730 __ GetObjectType(v0, a1, a1); |
2712 __ Branch(&non_function_constructor, ne, a1, Operand(JS_FUNCTION_TYPE)); | 2731 __ Branch(&non_function_constructor, ne, a1, Operand(JS_FUNCTION_TYPE)); |
2713 | 2732 |
2714 // v0 now contains the constructor function. Grab the | 2733 // v0 now contains the constructor function. Grab the |
2715 // instance class name from there. | 2734 // instance class name from there. |
2716 __ lw(v0, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset)); | 2735 __ lw(v0, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset)); |
2717 __ lw(v0, FieldMemOperand(v0, SharedFunctionInfo::kInstanceClassNameOffset)); | 2736 __ lw(v0, FieldMemOperand(v0, SharedFunctionInfo::kInstanceClassNameOffset)); |
2718 __ Branch(&done); | 2737 __ Branch(&done); |
2719 | 2738 |
(...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3186 1 << MemoryChunk::SCAN_ON_SCAVENGE, | 3205 1 << MemoryChunk::SCAN_ON_SCAVENGE, |
3187 ne, | 3206 ne, |
3188 &no_remembered_set); | 3207 &no_remembered_set); |
3189 // Possible optimization: do a check that both values are Smis | 3208 // Possible optimization: do a check that both values are Smis |
3190 // (or them and test against Smi mask). | 3209 // (or them and test against Smi mask). |
3191 | 3210 |
3192 // We are swapping two objects in an array and the incremental marker never | 3211 // We are swapping two objects in an array and the incremental marker never |
3193 // pauses in the middle of scanning a single object. Therefore the | 3212 // pauses in the middle of scanning a single object. Therefore the |
3194 // incremental marker is not disturbed, so we don't need to call the | 3213 // incremental marker is not disturbed, so we don't need to call the |
3195 // RecordWrite stub that notifies the incremental marker. | 3214 // RecordWrite stub that notifies the incremental marker. |
3196 __ RememberedSetHelper( | 3215 __ RememberedSetHelper(elements, |
3197 index1, scratch2, kDontSaveFPRegs, MacroAssembler::kFallThroughAtEnd); | 3216 index1, |
3198 __ RememberedSetHelper( | 3217 scratch2, |
3199 index2, scratch2, kDontSaveFPRegs, MacroAssembler::kFallThroughAtEnd); | 3218 kDontSaveFPRegs, |
| 3219 MacroAssembler::kFallThroughAtEnd); |
| 3220 __ RememberedSetHelper(elements, |
| 3221 index2, |
| 3222 scratch2, |
| 3223 kDontSaveFPRegs, |
| 3224 MacroAssembler::kFallThroughAtEnd); |
3200 | 3225 |
3201 __ bind(&no_remembered_set); | 3226 __ bind(&no_remembered_set); |
3202 // We are done. Drop elements from the stack, and return undefined. | 3227 // We are done. Drop elements from the stack, and return undefined. |
3203 __ Drop(3); | 3228 __ Drop(3); |
3204 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex); | 3229 __ LoadRoot(v0, Heap::kUndefinedValueRootIndex); |
3205 __ jmp(&done); | 3230 __ jmp(&done); |
3206 | 3231 |
3207 __ bind(&slow_case); | 3232 __ bind(&slow_case); |
3208 __ CallRuntime(Runtime::kSwapElements, 3); | 3233 __ CallRuntime(Runtime::kSwapElements, 3); |
3209 | 3234 |
(...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3996 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); | 4021 __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
3997 __ Branch(if_true, eq, v0, Operand(at)); | 4022 __ Branch(if_true, eq, v0, Operand(at)); |
3998 __ JumpIfSmi(v0, if_false); | 4023 __ JumpIfSmi(v0, if_false); |
3999 // Check for undetectable objects => true. | 4024 // Check for undetectable objects => true. |
4000 __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset)); | 4025 __ lw(v0, FieldMemOperand(v0, HeapObject::kMapOffset)); |
4001 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset)); | 4026 __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset)); |
4002 __ And(a1, a1, Operand(1 << Map::kIsUndetectable)); | 4027 __ And(a1, a1, Operand(1 << Map::kIsUndetectable)); |
4003 Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through); | 4028 Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through); |
4004 } else if (check->Equals(isolate()->heap()->function_symbol())) { | 4029 } else if (check->Equals(isolate()->heap()->function_symbol())) { |
4005 __ JumpIfSmi(v0, if_false); | 4030 __ JumpIfSmi(v0, if_false); |
4006 __ GetObjectType(v0, a1, v0); // Leave map in a1. | 4031 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
4007 Split(ge, v0, Operand(FIRST_CALLABLE_SPEC_OBJECT_TYPE), | 4032 __ GetObjectType(v0, v0, a1); |
4008 if_true, if_false, fall_through); | 4033 __ Branch(if_true, eq, a1, Operand(JS_FUNCTION_TYPE)); |
4009 | 4034 Split(eq, a1, Operand(JS_FUNCTION_PROXY_TYPE), |
| 4035 if_true, if_false, fall_through); |
4010 } else if (check->Equals(isolate()->heap()->object_symbol())) { | 4036 } else if (check->Equals(isolate()->heap()->object_symbol())) { |
4011 __ JumpIfSmi(v0, if_false); | 4037 __ JumpIfSmi(v0, if_false); |
4012 if (!FLAG_harmony_typeof) { | 4038 if (!FLAG_harmony_typeof) { |
4013 __ LoadRoot(at, Heap::kNullValueRootIndex); | 4039 __ LoadRoot(at, Heap::kNullValueRootIndex); |
4014 __ Branch(if_true, eq, v0, Operand(at)); | 4040 __ Branch(if_true, eq, v0, Operand(at)); |
4015 } | 4041 } |
4016 // Check for JS objects => true. | 4042 // Check for JS objects => true. |
4017 __ GetObjectType(v0, v0, a1); | 4043 __ GetObjectType(v0, v0, a1); |
4018 __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); | 4044 __ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
4019 __ lbu(a1, FieldMemOperand(v0, Map::kInstanceTypeOffset)); | 4045 __ lbu(a1, FieldMemOperand(v0, Map::kInstanceTypeOffset)); |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4271 *context_length = 0; | 4297 *context_length = 0; |
4272 return previous_; | 4298 return previous_; |
4273 } | 4299 } |
4274 | 4300 |
4275 | 4301 |
4276 #undef __ | 4302 #undef __ |
4277 | 4303 |
4278 } } // namespace v8::internal | 4304 } } // namespace v8::internal |
4279 | 4305 |
4280 #endif // V8_TARGET_ARCH_MIPS | 4306 #endif // V8_TARGET_ARCH_MIPS |
OLD | NEW |