| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 123 // o fp: our caller's frame pointer | 123 // o fp: our caller's frame pointer |
| 124 // o sp: stack pointer | 124 // o sp: stack pointer |
| 125 // o lr: return address | 125 // o lr: return address |
| 126 // | 126 // |
| 127 // The function builds a JS frame. Please see JavaScriptFrameConstants in | 127 // The function builds a JS frame. Please see JavaScriptFrameConstants in |
| 128 // frames-arm.h for its layout. | 128 // frames-arm.h for its layout. |
| 129 void FullCodeGenerator::Generate() { | 129 void FullCodeGenerator::Generate() { |
| 130 CompilationInfo* info = info_; | 130 CompilationInfo* info = info_; |
| 131 handler_table_ = | 131 handler_table_ = |
| 132 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); | 132 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); |
| 133 |
| 134 InitializeFeedbackVector(); |
| 135 |
| 133 profiling_counter_ = isolate()->factory()->NewCell( | 136 profiling_counter_ = isolate()->factory()->NewCell( |
| 134 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); | 137 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); |
| 135 SetFunctionPosition(function()); | 138 SetFunctionPosition(function()); |
| 136 Comment cmnt(masm_, "[ function compiled by full code generator"); | 139 Comment cmnt(masm_, "[ function compiled by full code generator"); |
| 137 | 140 |
| 138 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | 141 ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
| 139 | 142 |
| 140 #ifdef DEBUG | 143 #ifdef DEBUG |
| 141 if (strlen(FLAG_stop_at) > 0 && | 144 if (strlen(FLAG_stop_at) > 0 && |
| 142 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 145 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 } | 198 } |
| 196 } | 199 } |
| 197 | 200 |
| 198 bool function_in_register = true; | 201 bool function_in_register = true; |
| 199 | 202 |
| 200 // Possibly allocate a local context. | 203 // Possibly allocate a local context. |
| 201 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 204 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 202 if (heap_slots > 0) { | 205 if (heap_slots > 0) { |
| 203 // Argument to NewContext is the function, which is still in r1. | 206 // Argument to NewContext is the function, which is still in r1. |
| 204 Comment cmnt(masm_, "[ Allocate context"); | 207 Comment cmnt(masm_, "[ Allocate context"); |
| 205 __ push(r1); | |
| 206 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) { | 208 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) { |
| 209 __ push(r1); |
| 207 __ Push(info->scope()->GetScopeInfo()); | 210 __ Push(info->scope()->GetScopeInfo()); |
| 208 __ CallRuntime(Runtime::kNewGlobalContext, 2); | 211 __ CallRuntime(Runtime::kNewGlobalContext, 2); |
| 209 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 212 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 210 FastNewContextStub stub(heap_slots); | 213 FastNewContextStub stub(heap_slots); |
| 211 __ CallStub(&stub); | 214 __ CallStub(&stub); |
| 212 } else { | 215 } else { |
| 216 __ push(r1); |
| 213 __ CallRuntime(Runtime::kNewFunctionContext, 1); | 217 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
| 214 } | 218 } |
| 215 function_in_register = false; | 219 function_in_register = false; |
| 216 // Context is returned in both r0 and cp. It replaces the context | 220 // Context is returned in r0. It replaces the context passed to us. |
| 217 // passed to us. It's saved in the stack and kept live in cp. | 221 // It's saved in the stack and kept live in cp. |
| 218 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 222 __ mov(cp, r0); |
| 223 __ str(r0, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 219 // Copy any necessary parameters into the context. | 224 // Copy any necessary parameters into the context. |
| 220 int num_parameters = info->scope()->num_parameters(); | 225 int num_parameters = info->scope()->num_parameters(); |
| 221 for (int i = 0; i < num_parameters; i++) { | 226 for (int i = 0; i < num_parameters; i++) { |
| 222 Variable* var = scope()->parameter(i); | 227 Variable* var = scope()->parameter(i); |
| 223 if (var->IsContextSlot()) { | 228 if (var->IsContextSlot()) { |
| 224 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 229 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 225 (num_parameters - 1 - i) * kPointerSize; | 230 (num_parameters - 1 - i) * kPointerSize; |
| 226 // Load parameter from stack. | 231 // Load parameter from stack. |
| 227 __ ldr(r0, MemOperand(fp, parameter_offset)); | 232 __ ldr(r0, MemOperand(fp, parameter_offset)); |
| 228 // Store it in the context. | 233 // Store it in the context. |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 659 if (false_label_ != fall_through_) __ b(false_label_); | 664 if (false_label_ != fall_through_) __ b(false_label_); |
| 660 } | 665 } |
| 661 } | 666 } |
| 662 | 667 |
| 663 | 668 |
| 664 void FullCodeGenerator::DoTest(Expression* condition, | 669 void FullCodeGenerator::DoTest(Expression* condition, |
| 665 Label* if_true, | 670 Label* if_true, |
| 666 Label* if_false, | 671 Label* if_false, |
| 667 Label* fall_through) { | 672 Label* fall_through) { |
| 668 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); | 673 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); |
| 669 CallIC(ic, NOT_CONTEXTUAL, condition->test_id()); | 674 CallIC(ic, condition->test_id()); |
| 670 __ tst(result_register(), result_register()); | 675 __ tst(result_register(), result_register()); |
| 671 Split(ne, if_true, if_false, fall_through); | 676 Split(ne, if_true, if_false, fall_through); |
| 672 } | 677 } |
| 673 | 678 |
| 674 | 679 |
| 675 void FullCodeGenerator::Split(Condition cond, | 680 void FullCodeGenerator::Split(Condition cond, |
| 676 Label* if_true, | 681 Label* if_true, |
| 677 Label* if_false, | 682 Label* if_false, |
| 678 Label* fall_through) { | 683 Label* fall_through) { |
| 679 if (if_false == fall_through) { | 684 if (if_false == fall_through) { |
| (...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1020 __ cmp(r1, r0); | 1025 __ cmp(r1, r0); |
| 1021 __ b(ne, &next_test); | 1026 __ b(ne, &next_test); |
| 1022 __ Drop(1); // Switch value is no longer needed. | 1027 __ Drop(1); // Switch value is no longer needed. |
| 1023 __ b(clause->body_target()); | 1028 __ b(clause->body_target()); |
| 1024 __ bind(&slow_case); | 1029 __ bind(&slow_case); |
| 1025 } | 1030 } |
| 1026 | 1031 |
| 1027 // Record position before stub call for type feedback. | 1032 // Record position before stub call for type feedback. |
| 1028 SetSourcePosition(clause->position()); | 1033 SetSourcePosition(clause->position()); |
| 1029 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); | 1034 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); |
| 1030 CallIC(ic, NOT_CONTEXTUAL, clause->CompareId()); | 1035 CallIC(ic, clause->CompareId()); |
| 1031 patch_site.EmitPatchInfo(); | 1036 patch_site.EmitPatchInfo(); |
| 1032 | 1037 |
| 1033 Label skip; | 1038 Label skip; |
| 1034 __ b(&skip); | 1039 __ b(&skip); |
| 1035 PrepareForBailout(clause, TOS_REG); | 1040 PrepareForBailout(clause, TOS_REG); |
| 1036 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 1041 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
| 1037 __ cmp(r0, ip); | 1042 __ cmp(r0, ip); |
| 1038 __ b(ne, &next_test); | 1043 __ b(ne, &next_test); |
| 1039 __ Drop(1); | 1044 __ Drop(1); |
| 1040 __ jmp(clause->body_target()); | 1045 __ jmp(clause->body_target()); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 1065 VisitStatements(clause->statements()); | 1070 VisitStatements(clause->statements()); |
| 1066 } | 1071 } |
| 1067 | 1072 |
| 1068 __ bind(nested_statement.break_label()); | 1073 __ bind(nested_statement.break_label()); |
| 1069 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); | 1074 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 1070 } | 1075 } |
| 1071 | 1076 |
| 1072 | 1077 |
| 1073 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 1078 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 1074 Comment cmnt(masm_, "[ ForInStatement"); | 1079 Comment cmnt(masm_, "[ ForInStatement"); |
| 1080 int slot = stmt->ForInFeedbackSlot(); |
| 1075 SetStatementPosition(stmt); | 1081 SetStatementPosition(stmt); |
| 1076 | 1082 |
| 1077 Label loop, exit; | 1083 Label loop, exit; |
| 1078 ForIn loop_statement(this, stmt); | 1084 ForIn loop_statement(this, stmt); |
| 1079 increment_loop_depth(); | 1085 increment_loop_depth(); |
| 1080 | 1086 |
| 1081 // Get the object to enumerate over. If the object is null or undefined, skip | 1087 // Get the object to enumerate over. If the object is null or undefined, skip |
| 1082 // over the loop. See ECMA-262 version 5, section 12.6.4. | 1088 // over the loop. See ECMA-262 version 5, section 12.6.4. |
| 1083 VisitForAccumulatorValue(stmt->enumerable()); | 1089 VisitForAccumulatorValue(stmt->enumerable()); |
| 1084 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 1090 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1154 __ jmp(&loop); | 1160 __ jmp(&loop); |
| 1155 | 1161 |
| 1156 __ bind(&no_descriptors); | 1162 __ bind(&no_descriptors); |
| 1157 __ Drop(1); | 1163 __ Drop(1); |
| 1158 __ jmp(&exit); | 1164 __ jmp(&exit); |
| 1159 | 1165 |
| 1160 // We got a fixed array in register r0. Iterate through that. | 1166 // We got a fixed array in register r0. Iterate through that. |
| 1161 Label non_proxy; | 1167 Label non_proxy; |
| 1162 __ bind(&fixed_array); | 1168 __ bind(&fixed_array); |
| 1163 | 1169 |
| 1164 Handle<Cell> cell = isolate()->factory()->NewCell( | 1170 Handle<Object> feedback = Handle<Object>( |
| 1165 Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), | 1171 Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker), |
| 1166 isolate())); | 1172 isolate()); |
| 1167 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); | 1173 StoreFeedbackVectorSlot(slot, feedback); |
| 1168 __ Move(r1, cell); | 1174 __ Move(r1, FeedbackVector()); |
| 1169 __ mov(r2, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); | 1175 __ mov(r2, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker))); |
| 1170 __ str(r2, FieldMemOperand(r1, Cell::kValueOffset)); | 1176 __ str(r2, FieldMemOperand(r1, FixedArray::OffsetOfElementAt(slot))); |
| 1171 | 1177 |
| 1172 __ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check | 1178 __ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check |
| 1173 __ ldr(r2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object | 1179 __ ldr(r2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object |
| 1174 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 1180 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 1175 __ CompareObjectType(r2, r3, r3, LAST_JS_PROXY_TYPE); | 1181 __ CompareObjectType(r2, r3, r3, LAST_JS_PROXY_TYPE); |
| 1176 __ b(gt, &non_proxy); | 1182 __ b(gt, &non_proxy); |
| 1177 __ mov(r1, Operand(Smi::FromInt(0))); // Zero indicates proxy | 1183 __ mov(r1, Operand(Smi::FromInt(0))); // Zero indicates proxy |
| 1178 __ bind(&non_proxy); | 1184 __ bind(&non_proxy); |
| 1179 __ Push(r1, r0); // Smi and array | 1185 __ Push(r1, r0); // Smi and array |
| 1180 __ ldr(r1, FieldMemOperand(r0, FixedArray::kLengthOffset)); | 1186 __ ldr(r1, FieldMemOperand(r0, FixedArray::kLengthOffset)); |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1469 | 1475 |
| 1470 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1476 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
| 1471 // Record position before possible IC call. | 1477 // Record position before possible IC call. |
| 1472 SetSourcePosition(proxy->position()); | 1478 SetSourcePosition(proxy->position()); |
| 1473 Variable* var = proxy->var(); | 1479 Variable* var = proxy->var(); |
| 1474 | 1480 |
| 1475 // Three cases: global variables, lookup variables, and all other types of | 1481 // Three cases: global variables, lookup variables, and all other types of |
| 1476 // variables. | 1482 // variables. |
| 1477 switch (var->location()) { | 1483 switch (var->location()) { |
| 1478 case Variable::UNALLOCATED: { | 1484 case Variable::UNALLOCATED: { |
| 1479 Comment cmnt(masm_, "Global variable"); | 1485 Comment cmnt(masm_, "[ Global variable"); |
| 1480 // Use inline caching. Variable name is passed in r2 and the global | 1486 // Use inline caching. Variable name is passed in r2 and the global |
| 1481 // object (receiver) in r0. | 1487 // object (receiver) in r0. |
| 1482 __ ldr(r0, GlobalObjectOperand()); | 1488 __ ldr(r0, GlobalObjectOperand()); |
| 1483 __ mov(r2, Operand(var->name())); | 1489 __ mov(r2, Operand(var->name())); |
| 1484 CallLoadIC(CONTEXTUAL); | 1490 CallLoadIC(CONTEXTUAL); |
| 1485 context()->Plug(r0); | 1491 context()->Plug(r0); |
| 1486 break; | 1492 break; |
| 1487 } | 1493 } |
| 1488 | 1494 |
| 1489 case Variable::PARAMETER: | 1495 case Variable::PARAMETER: |
| 1490 case Variable::LOCAL: | 1496 case Variable::LOCAL: |
| 1491 case Variable::CONTEXT: { | 1497 case Variable::CONTEXT: { |
| 1492 Comment cmnt(masm_, var->IsContextSlot() | 1498 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" |
| 1493 ? "Context variable" | 1499 : "[ Stack variable"); |
| 1494 : "Stack variable"); | |
| 1495 if (var->binding_needs_init()) { | 1500 if (var->binding_needs_init()) { |
| 1496 // var->scope() may be NULL when the proxy is located in eval code and | 1501 // var->scope() may be NULL when the proxy is located in eval code and |
| 1497 // refers to a potential outside binding. Currently those bindings are | 1502 // refers to a potential outside binding. Currently those bindings are |
| 1498 // always looked up dynamically, i.e. in that case | 1503 // always looked up dynamically, i.e. in that case |
| 1499 // var->location() == LOOKUP. | 1504 // var->location() == LOOKUP. |
| 1500 // always holds. | 1505 // always holds. |
| 1501 ASSERT(var->scope() != NULL); | 1506 ASSERT(var->scope() != NULL); |
| 1502 | 1507 |
| 1503 // Check if the binding really needs an initialization check. The check | 1508 // Check if the binding really needs an initialization check. The check |
| 1504 // can be skipped in the following situation: we have a LET or CONST | 1509 // can be skipped in the following situation: we have a LET or CONST |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1547 } | 1552 } |
| 1548 context()->Plug(r0); | 1553 context()->Plug(r0); |
| 1549 break; | 1554 break; |
| 1550 } | 1555 } |
| 1551 } | 1556 } |
| 1552 context()->Plug(var); | 1557 context()->Plug(var); |
| 1553 break; | 1558 break; |
| 1554 } | 1559 } |
| 1555 | 1560 |
| 1556 case Variable::LOOKUP: { | 1561 case Variable::LOOKUP: { |
| 1562 Comment cmnt(masm_, "[ Lookup variable"); |
| 1557 Label done, slow; | 1563 Label done, slow; |
| 1558 // Generate code for loading from variables potentially shadowed | 1564 // Generate code for loading from variables potentially shadowed |
| 1559 // by eval-introduced variables. | 1565 // by eval-introduced variables. |
| 1560 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); | 1566 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1561 __ bind(&slow); | 1567 __ bind(&slow); |
| 1562 Comment cmnt(masm_, "Lookup variable"); | |
| 1563 __ mov(r1, Operand(var->name())); | 1568 __ mov(r1, Operand(var->name())); |
| 1564 __ Push(cp, r1); // Context and name. | 1569 __ Push(cp, r1); // Context and name. |
| 1565 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1570 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1566 __ bind(&done); | 1571 __ bind(&done); |
| 1567 context()->Plug(r0); | 1572 context()->Plug(r0); |
| 1568 } | 1573 } |
| 1569 } | 1574 } |
| 1570 } | 1575 } |
| 1571 | 1576 |
| 1572 | 1577 |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1683 UNREACHABLE(); | 1688 UNREACHABLE(); |
| 1684 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1689 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 1685 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); | 1690 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); |
| 1686 // Fall through. | 1691 // Fall through. |
| 1687 case ObjectLiteral::Property::COMPUTED: | 1692 case ObjectLiteral::Property::COMPUTED: |
| 1688 if (key->value()->IsInternalizedString()) { | 1693 if (key->value()->IsInternalizedString()) { |
| 1689 if (property->emit_store()) { | 1694 if (property->emit_store()) { |
| 1690 VisitForAccumulatorValue(value); | 1695 VisitForAccumulatorValue(value); |
| 1691 __ mov(r2, Operand(key->value())); | 1696 __ mov(r2, Operand(key->value())); |
| 1692 __ ldr(r1, MemOperand(sp)); | 1697 __ ldr(r1, MemOperand(sp)); |
| 1693 CallStoreIC(NOT_CONTEXTUAL, key->LiteralFeedbackId()); | 1698 CallStoreIC(key->LiteralFeedbackId()); |
| 1694 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1699 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1695 } else { | 1700 } else { |
| 1696 VisitForEffect(value); | 1701 VisitForEffect(value); |
| 1697 } | 1702 } |
| 1698 break; | 1703 break; |
| 1699 } | 1704 } |
| 1700 // Duplicate receiver on stack. | 1705 // Duplicate receiver on stack. |
| 1701 __ ldr(r0, MemOperand(sp)); | 1706 __ ldr(r0, MemOperand(sp)); |
| 1702 __ push(r0); | 1707 __ push(r0); |
| 1703 VisitForStackValue(key); | 1708 VisitForStackValue(key); |
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2040 | 2045 |
| 2041 Label l_catch, l_try, l_suspend, l_continuation, l_resume; | 2046 Label l_catch, l_try, l_suspend, l_continuation, l_resume; |
| 2042 Label l_next, l_call, l_loop; | 2047 Label l_next, l_call, l_loop; |
| 2043 // Initial send value is undefined. | 2048 // Initial send value is undefined. |
| 2044 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 2049 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
| 2045 __ b(&l_next); | 2050 __ b(&l_next); |
| 2046 | 2051 |
| 2047 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; } | 2052 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; } |
| 2048 __ bind(&l_catch); | 2053 __ bind(&l_catch); |
| 2049 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); | 2054 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); |
| 2050 __ LoadRoot(r2, Heap::kthrow_stringRootIndex); // "throw" | 2055 __ LoadRoot(r2, Heap::kthrow_stringRootIndex); // "throw" |
| 2051 __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter | 2056 __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter |
| 2052 __ Push(r3, r0); // iter, exception | 2057 __ Push(r2, r3, r0); // "throw", iter, except |
| 2053 __ jmp(&l_call); | 2058 __ jmp(&l_call); |
| 2054 | 2059 |
| 2055 // try { received = %yield result } | 2060 // try { received = %yield result } |
| 2056 // Shuffle the received result above a try handler and yield it without | 2061 // Shuffle the received result above a try handler and yield it without |
| 2057 // re-boxing. | 2062 // re-boxing. |
| 2058 __ bind(&l_try); | 2063 __ bind(&l_try); |
| 2059 __ pop(r0); // result | 2064 __ pop(r0); // result |
| 2060 __ PushTryHandler(StackHandler::CATCH, expr->index()); | 2065 __ PushTryHandler(StackHandler::CATCH, expr->index()); |
| 2061 const int handler_size = StackHandlerConstants::kSize; | 2066 const int handler_size = StackHandlerConstants::kSize; |
| 2062 __ push(r0); // result | 2067 __ push(r0); // result |
| 2063 __ jmp(&l_suspend); | 2068 __ jmp(&l_suspend); |
| 2064 __ bind(&l_continuation); | 2069 __ bind(&l_continuation); |
| 2065 __ jmp(&l_resume); | 2070 __ jmp(&l_resume); |
| 2066 __ bind(&l_suspend); | 2071 __ bind(&l_suspend); |
| 2067 const int generator_object_depth = kPointerSize + handler_size; | 2072 const int generator_object_depth = kPointerSize + handler_size; |
| 2068 __ ldr(r0, MemOperand(sp, generator_object_depth)); | 2073 __ ldr(r0, MemOperand(sp, generator_object_depth)); |
| 2069 __ push(r0); // g | 2074 __ push(r0); // g |
| 2070 ASSERT(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos())); | 2075 ASSERT(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos())); |
| 2071 __ mov(r1, Operand(Smi::FromInt(l_continuation.pos()))); | 2076 __ mov(r1, Operand(Smi::FromInt(l_continuation.pos()))); |
| 2072 __ str(r1, FieldMemOperand(r0, JSGeneratorObject::kContinuationOffset)); | 2077 __ str(r1, FieldMemOperand(r0, JSGeneratorObject::kContinuationOffset)); |
| 2073 __ str(cp, FieldMemOperand(r0, JSGeneratorObject::kContextOffset)); | 2078 __ str(cp, FieldMemOperand(r0, JSGeneratorObject::kContextOffset)); |
| 2074 __ mov(r1, cp); | 2079 __ mov(r1, cp); |
| 2075 __ RecordWriteField(r0, JSGeneratorObject::kContextOffset, r1, r2, | 2080 __ RecordWriteField(r0, JSGeneratorObject::kContextOffset, r1, r2, |
| 2076 kLRHasBeenSaved, kDontSaveFPRegs); | 2081 kLRHasBeenSaved, kDontSaveFPRegs); |
| 2077 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); | 2082 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); |
| 2078 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2083 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2079 __ pop(r0); // result | 2084 __ pop(r0); // result |
| 2080 EmitReturnSequence(); | 2085 EmitReturnSequence(); |
| 2081 __ bind(&l_resume); // received in r0 | 2086 __ bind(&l_resume); // received in r0 |
| 2082 __ PopTryHandler(); | 2087 __ PopTryHandler(); |
| 2083 | 2088 |
| 2084 // receiver = iter; f = 'next'; arg = received; | 2089 // receiver = iter; f = 'next'; arg = received; |
| 2085 __ bind(&l_next); | 2090 __ bind(&l_next); |
| 2086 __ LoadRoot(r2, Heap::knext_stringRootIndex); // "next" | 2091 __ LoadRoot(r2, Heap::knext_stringRootIndex); // "next" |
| 2087 __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter | 2092 __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter |
| 2088 __ Push(r3, r0); // iter, received | 2093 __ Push(r2, r3, r0); // "next", iter, received |
| 2089 | 2094 |
| 2090 // result = receiver[f](arg); | 2095 // result = receiver[f](arg); |
| 2091 __ bind(&l_call); | 2096 __ bind(&l_call); |
| 2092 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); | 2097 __ ldr(r1, MemOperand(sp, kPointerSize)); |
| 2093 CallIC(ic); | 2098 __ ldr(r0, MemOperand(sp, 2 * kPointerSize)); |
| 2099 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2100 CallIC(ic, TypeFeedbackId::None()); |
| 2101 __ mov(r1, r0); |
| 2102 __ str(r1, MemOperand(sp, 2 * kPointerSize)); |
| 2103 CallFunctionStub stub(1, CALL_AS_METHOD); |
| 2104 __ CallStub(&stub); |
| 2105 |
| 2094 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2106 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2107 __ Drop(1); // The function is still on the stack; drop it. |
| 2095 | 2108 |
| 2096 // if (!result.done) goto l_try; | 2109 // if (!result.done) goto l_try; |
| 2097 __ bind(&l_loop); | 2110 __ bind(&l_loop); |
| 2098 __ push(r0); // save result | 2111 __ push(r0); // save result |
| 2099 __ LoadRoot(r2, Heap::kdone_stringRootIndex); // "done" | 2112 __ LoadRoot(r2, Heap::kdone_stringRootIndex); // "done" |
| 2100 CallLoadIC(NOT_CONTEXTUAL); // result.done in r0 | 2113 CallLoadIC(NOT_CONTEXTUAL); // result.done in r0 |
| 2101 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); | 2114 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); |
| 2102 CallIC(bool_ic); | 2115 CallIC(bool_ic); |
| 2103 __ cmp(r0, Operand(0)); | 2116 __ cmp(r0, Operand(0)); |
| 2104 __ b(eq, &l_try); | 2117 __ b(eq, &l_try); |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2274 __ mov(r2, Operand(key->value())); | 2287 __ mov(r2, Operand(key->value())); |
| 2275 // Call load IC. It has arguments receiver and property name r0 and r2. | 2288 // Call load IC. It has arguments receiver and property name r0 and r2. |
| 2276 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); | 2289 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); |
| 2277 } | 2290 } |
| 2278 | 2291 |
| 2279 | 2292 |
| 2280 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 2293 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 2281 SetSourcePosition(prop->position()); | 2294 SetSourcePosition(prop->position()); |
| 2282 // Call keyed load IC. It has arguments key and receiver in r0 and r1. | 2295 // Call keyed load IC. It has arguments key and receiver in r0 and r1. |
| 2283 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 2296 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2284 CallIC(ic, NOT_CONTEXTUAL, prop->PropertyFeedbackId()); | 2297 CallIC(ic, prop->PropertyFeedbackId()); |
| 2285 } | 2298 } |
| 2286 | 2299 |
| 2287 | 2300 |
| 2288 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, | 2301 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, |
| 2289 Token::Value op, | 2302 Token::Value op, |
| 2290 OverwriteMode mode, | 2303 OverwriteMode mode, |
| 2291 Expression* left_expr, | 2304 Expression* left_expr, |
| 2292 Expression* right_expr) { | 2305 Expression* right_expr) { |
| 2293 Label done, smi_case, stub_call; | 2306 Label done, smi_case, stub_call; |
| 2294 | 2307 |
| 2295 Register scratch1 = r2; | 2308 Register scratch1 = r2; |
| 2296 Register scratch2 = r3; | 2309 Register scratch2 = r3; |
| 2297 | 2310 |
| 2298 // Get the arguments. | 2311 // Get the arguments. |
| 2299 Register left = r1; | 2312 Register left = r1; |
| 2300 Register right = r0; | 2313 Register right = r0; |
| 2301 __ pop(left); | 2314 __ pop(left); |
| 2302 | 2315 |
| 2303 // Perform combined smi check on both operands. | 2316 // Perform combined smi check on both operands. |
| 2304 __ orr(scratch1, left, Operand(right)); | 2317 __ orr(scratch1, left, Operand(right)); |
| 2305 STATIC_ASSERT(kSmiTag == 0); | 2318 STATIC_ASSERT(kSmiTag == 0); |
| 2306 JumpPatchSite patch_site(masm_); | 2319 JumpPatchSite patch_site(masm_); |
| 2307 patch_site.EmitJumpIfSmi(scratch1, &smi_case); | 2320 patch_site.EmitJumpIfSmi(scratch1, &smi_case); |
| 2308 | 2321 |
| 2309 __ bind(&stub_call); | 2322 __ bind(&stub_call); |
| 2310 BinaryOpICStub stub(op, mode); | 2323 BinaryOpICStub stub(op, mode); |
| 2311 CallIC(stub.GetCode(isolate()), NOT_CONTEXTUAL, | 2324 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId()); |
| 2312 expr->BinaryOperationFeedbackId()); | |
| 2313 patch_site.EmitPatchInfo(); | 2325 patch_site.EmitPatchInfo(); |
| 2314 __ jmp(&done); | 2326 __ jmp(&done); |
| 2315 | 2327 |
| 2316 __ bind(&smi_case); | 2328 __ bind(&smi_case); |
| 2317 // Smi case. This code works the same way as the smi-smi case in the type | 2329 // Smi case. This code works the same way as the smi-smi case in the type |
| 2318 // recording binary operation stub, see | 2330 // recording binary operation stub, see |
| 2319 switch (op) { | 2331 switch (op) { |
| 2320 case Token::SAR: | 2332 case Token::SAR: |
| 2321 __ GetLeastBitsFromSmi(scratch1, right, 5); | 2333 __ GetLeastBitsFromSmi(scratch1, right, 5); |
| 2322 __ mov(right, Operand(left, ASR, scratch1)); | 2334 __ mov(right, Operand(left, ASR, scratch1)); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2379 context()->Plug(r0); | 2391 context()->Plug(r0); |
| 2380 } | 2392 } |
| 2381 | 2393 |
| 2382 | 2394 |
| 2383 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, | 2395 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, |
| 2384 Token::Value op, | 2396 Token::Value op, |
| 2385 OverwriteMode mode) { | 2397 OverwriteMode mode) { |
| 2386 __ pop(r1); | 2398 __ pop(r1); |
| 2387 BinaryOpICStub stub(op, mode); | 2399 BinaryOpICStub stub(op, mode); |
| 2388 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. | 2400 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
| 2389 CallIC(stub.GetCode(isolate()), NOT_CONTEXTUAL, | 2401 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId()); |
| 2390 expr->BinaryOperationFeedbackId()); | |
| 2391 patch_site.EmitPatchInfo(); | 2402 patch_site.EmitPatchInfo(); |
| 2392 context()->Plug(r0); | 2403 context()->Plug(r0); |
| 2393 } | 2404 } |
| 2394 | 2405 |
| 2395 | 2406 |
| 2396 void FullCodeGenerator::EmitAssignment(Expression* expr) { | 2407 void FullCodeGenerator::EmitAssignment(Expression* expr) { |
| 2397 // Invalid left-hand sides are rewritten by the parser to have a 'throw | 2408 // Invalid left-hand sides are rewritten by the parser to have a 'throw |
| 2398 // ReferenceError' on the left-hand side. | 2409 // ReferenceError' on the left-hand side. |
| 2399 if (!expr->IsValidLeftHandSide()) { | 2410 if (!expr->IsValidLeftHandSide()) { |
| 2400 VisitForEffect(expr); | 2411 VisitForEffect(expr); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2418 EffectContext context(this); | 2429 EffectContext context(this); |
| 2419 EmitVariableAssignment(var, Token::ASSIGN); | 2430 EmitVariableAssignment(var, Token::ASSIGN); |
| 2420 break; | 2431 break; |
| 2421 } | 2432 } |
| 2422 case NAMED_PROPERTY: { | 2433 case NAMED_PROPERTY: { |
| 2423 __ push(r0); // Preserve value. | 2434 __ push(r0); // Preserve value. |
| 2424 VisitForAccumulatorValue(prop->obj()); | 2435 VisitForAccumulatorValue(prop->obj()); |
| 2425 __ mov(r1, r0); | 2436 __ mov(r1, r0); |
| 2426 __ pop(r0); // Restore value. | 2437 __ pop(r0); // Restore value. |
| 2427 __ mov(r2, Operand(prop->key()->AsLiteral()->value())); | 2438 __ mov(r2, Operand(prop->key()->AsLiteral()->value())); |
| 2428 CallStoreIC(NOT_CONTEXTUAL); | 2439 CallStoreIC(); |
| 2429 break; | 2440 break; |
| 2430 } | 2441 } |
| 2431 case KEYED_PROPERTY: { | 2442 case KEYED_PROPERTY: { |
| 2432 __ push(r0); // Preserve value. | 2443 __ push(r0); // Preserve value. |
| 2433 VisitForStackValue(prop->obj()); | 2444 VisitForStackValue(prop->obj()); |
| 2434 VisitForAccumulatorValue(prop->key()); | 2445 VisitForAccumulatorValue(prop->key()); |
| 2435 __ mov(r1, r0); | 2446 __ mov(r1, r0); |
| 2436 __ Pop(r0, r2); // r0 = restored value. | 2447 __ Pop(r0, r2); // r0 = restored value. |
| 2437 Handle<Code> ic = is_classic_mode() | 2448 Handle<Code> ic = is_classic_mode() |
| 2438 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2449 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2439 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2450 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2440 CallIC(ic); | 2451 CallIC(ic); |
| 2441 break; | 2452 break; |
| 2442 } | 2453 } |
| 2443 } | 2454 } |
| 2444 context()->Plug(r0); | 2455 context()->Plug(r0); |
| 2445 } | 2456 } |
| 2446 | 2457 |
| 2447 | 2458 |
| 2459 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( |
| 2460 Variable* var, MemOperand location) { |
| 2461 __ str(result_register(), location); |
| 2462 if (var->IsContextSlot()) { |
| 2463 // RecordWrite may destroy all its register arguments. |
| 2464 __ mov(r3, result_register()); |
| 2465 int offset = Context::SlotOffset(var->index()); |
| 2466 __ RecordWriteContextSlot( |
| 2467 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs); |
| 2468 } |
| 2469 } |
| 2470 |
| 2471 |
| 2472 void FullCodeGenerator::EmitCallStoreContextSlot( |
| 2473 Handle<String> name, LanguageMode mode) { |
| 2474 __ push(r0); // Value. |
| 2475 __ mov(r1, Operand(name)); |
| 2476 __ mov(r0, Operand(Smi::FromInt(mode))); |
| 2477 __ Push(cp, r1, r0); // Context, name, strict mode. |
| 2478 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
| 2479 } |
| 2480 |
| 2481 |
| 2448 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 2482 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 2449 Token::Value op) { | 2483 Token::Value op) { |
| 2450 if (var->IsUnallocated()) { | 2484 if (var->IsUnallocated()) { |
| 2451 // Global var, const, or let. | 2485 // Global var, const, or let. |
| 2452 __ mov(r2, Operand(var->name())); | 2486 __ mov(r2, Operand(var->name())); |
| 2453 __ ldr(r1, GlobalObjectOperand()); | 2487 __ ldr(r1, GlobalObjectOperand()); |
| 2454 CallStoreIC(CONTEXTUAL); | 2488 CallStoreIC(); |
| 2489 |
| 2455 } else if (op == Token::INIT_CONST) { | 2490 } else if (op == Token::INIT_CONST) { |
| 2456 // Const initializers need a write barrier. | 2491 // Const initializers need a write barrier. |
| 2457 ASSERT(!var->IsParameter()); // No const parameters. | 2492 ASSERT(!var->IsParameter()); // No const parameters. |
| 2458 if (var->IsStackLocal()) { | 2493 if (var->IsLookupSlot()) { |
| 2459 __ ldr(r1, StackOperand(var)); | |
| 2460 __ CompareRoot(r1, Heap::kTheHoleValueRootIndex); | |
| 2461 __ str(result_register(), StackOperand(var), eq); | |
| 2462 } else { | |
| 2463 ASSERT(var->IsContextSlot() || var->IsLookupSlot()); | |
| 2464 // Like var declarations, const declarations are hoisted to function | |
| 2465 // scope. However, unlike var initializers, const initializers are | |
| 2466 // able to drill a hole to that function context, even from inside a | |
| 2467 // 'with' context. We thus bypass the normal static scope lookup for | |
| 2468 // var->IsContextSlot(). | |
| 2469 __ push(r0); | 2494 __ push(r0); |
| 2470 __ mov(r0, Operand(var->name())); | 2495 __ mov(r0, Operand(var->name())); |
| 2471 __ Push(cp, r0); // Context and name. | 2496 __ Push(cp, r0); // Context and name. |
| 2472 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 2497 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 2498 } else { |
| 2499 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
| 2500 Label skip; |
| 2501 MemOperand location = VarOperand(var, r1); |
| 2502 __ ldr(r2, location); |
| 2503 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); |
| 2504 __ b(ne, &skip); |
| 2505 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2506 __ bind(&skip); |
| 2473 } | 2507 } |
| 2474 | 2508 |
| 2475 } else if (var->mode() == LET && op != Token::INIT_LET) { | 2509 } else if (var->mode() == LET && op != Token::INIT_LET) { |
| 2476 // Non-initializing assignment to let variable needs a write barrier. | 2510 // Non-initializing assignment to let variable needs a write barrier. |
| 2477 if (var->IsLookupSlot()) { | 2511 if (var->IsLookupSlot()) { |
| 2478 __ push(r0); // Value. | 2512 EmitCallStoreContextSlot(var->name(), language_mode()); |
| 2479 __ mov(r1, Operand(var->name())); | |
| 2480 __ mov(r0, Operand(Smi::FromInt(language_mode()))); | |
| 2481 __ Push(cp, r1, r0); // Context, name, strict mode. | |
| 2482 __ CallRuntime(Runtime::kStoreContextSlot, 4); | |
| 2483 } else { | 2513 } else { |
| 2484 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2514 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
| 2485 Label assign; | 2515 Label assign; |
| 2486 MemOperand location = VarOperand(var, r1); | 2516 MemOperand location = VarOperand(var, r1); |
| 2487 __ ldr(r3, location); | 2517 __ ldr(r3, location); |
| 2488 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); | 2518 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); |
| 2489 __ b(ne, &assign); | 2519 __ b(ne, &assign); |
| 2490 __ mov(r3, Operand(var->name())); | 2520 __ mov(r3, Operand(var->name())); |
| 2491 __ push(r3); | 2521 __ push(r3); |
| 2492 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 2522 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 2493 // Perform the assignment. | 2523 // Perform the assignment. |
| 2494 __ bind(&assign); | 2524 __ bind(&assign); |
| 2495 __ str(result_register(), location); | 2525 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2496 if (var->IsContextSlot()) { | |
| 2497 // RecordWrite may destroy all its register arguments. | |
| 2498 __ mov(r3, result_register()); | |
| 2499 int offset = Context::SlotOffset(var->index()); | |
| 2500 __ RecordWriteContextSlot( | |
| 2501 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs); | |
| 2502 } | |
| 2503 } | 2526 } |
| 2504 | 2527 |
| 2505 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { | 2528 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { |
| 2506 // Assignment to var or initializing assignment to let/const | 2529 // Assignment to var or initializing assignment to let/const |
| 2507 // in harmony mode. | 2530 // in harmony mode. |
| 2508 if (var->IsStackAllocated() || var->IsContextSlot()) { | 2531 if (var->IsLookupSlot()) { |
| 2532 EmitCallStoreContextSlot(var->name(), language_mode()); |
| 2533 } else { |
| 2534 ASSERT((var->IsStackAllocated() || var->IsContextSlot())); |
| 2509 MemOperand location = VarOperand(var, r1); | 2535 MemOperand location = VarOperand(var, r1); |
| 2510 if (generate_debug_code_ && op == Token::INIT_LET) { | 2536 if (generate_debug_code_ && op == Token::INIT_LET) { |
| 2511 // Check for an uninitialized let binding. | 2537 // Check for an uninitialized let binding. |
| 2512 __ ldr(r2, location); | 2538 __ ldr(r2, location); |
| 2513 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); | 2539 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex); |
| 2514 __ Check(eq, kLetBindingReInitialization); | 2540 __ Check(eq, kLetBindingReInitialization); |
| 2515 } | 2541 } |
| 2516 // Perform the assignment. | 2542 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2517 __ str(r0, location); | |
| 2518 if (var->IsContextSlot()) { | |
| 2519 __ mov(r3, r0); | |
| 2520 int offset = Context::SlotOffset(var->index()); | |
| 2521 __ RecordWriteContextSlot( | |
| 2522 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs); | |
| 2523 } | |
| 2524 } else { | |
| 2525 ASSERT(var->IsLookupSlot()); | |
| 2526 __ push(r0); // Value. | |
| 2527 __ mov(r1, Operand(var->name())); | |
| 2528 __ mov(r0, Operand(Smi::FromInt(language_mode()))); | |
| 2529 __ Push(cp, r1, r0); // Context, name, strict mode. | |
| 2530 __ CallRuntime(Runtime::kStoreContextSlot, 4); | |
| 2531 } | 2543 } |
| 2532 } | 2544 } |
| 2533 // Non-initializing assignments to consts are ignored. | 2545 // Non-initializing assignments to consts are ignored. |
| 2534 } | 2546 } |
| 2535 | 2547 |
| 2536 | 2548 |
| 2537 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 2549 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 2538 // Assignment to a property, using a named store IC. | 2550 // Assignment to a property, using a named store IC. |
| 2539 Property* prop = expr->target()->AsProperty(); | 2551 Property* prop = expr->target()->AsProperty(); |
| 2540 ASSERT(prop != NULL); | 2552 ASSERT(prop != NULL); |
| 2541 ASSERT(prop->key()->AsLiteral() != NULL); | 2553 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2542 | 2554 |
| 2543 // Record source code position before IC call. | 2555 // Record source code position before IC call. |
| 2544 SetSourcePosition(expr->position()); | 2556 SetSourcePosition(expr->position()); |
| 2545 __ mov(r2, Operand(prop->key()->AsLiteral()->value())); | 2557 __ mov(r2, Operand(prop->key()->AsLiteral()->value())); |
| 2546 __ pop(r1); | 2558 __ pop(r1); |
| 2547 | 2559 |
| 2548 CallStoreIC(NOT_CONTEXTUAL, expr->AssignmentFeedbackId()); | 2560 CallStoreIC(expr->AssignmentFeedbackId()); |
| 2549 | 2561 |
| 2550 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2562 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2551 context()->Plug(r0); | 2563 context()->Plug(r0); |
| 2552 } | 2564 } |
| 2553 | 2565 |
| 2554 | 2566 |
| 2555 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 2567 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
| 2556 // Assignment to a property, using a keyed store IC. | 2568 // Assignment to a property, using a keyed store IC. |
| 2557 | 2569 |
| 2558 // Record source code position before IC call. | 2570 // Record source code position before IC call. |
| 2559 SetSourcePosition(expr->position()); | 2571 SetSourcePosition(expr->position()); |
| 2560 __ Pop(r2, r1); // r1 = key. | 2572 __ Pop(r2, r1); // r1 = key. |
| 2561 | 2573 |
| 2562 Handle<Code> ic = is_classic_mode() | 2574 Handle<Code> ic = is_classic_mode() |
| 2563 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2575 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2564 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2576 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2565 CallIC(ic, NOT_CONTEXTUAL, expr->AssignmentFeedbackId()); | 2577 CallIC(ic, expr->AssignmentFeedbackId()); |
| 2566 | 2578 |
| 2567 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2579 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2568 context()->Plug(r0); | 2580 context()->Plug(r0); |
| 2569 } | 2581 } |
| 2570 | 2582 |
| 2571 | 2583 |
| 2572 void FullCodeGenerator::VisitProperty(Property* expr) { | 2584 void FullCodeGenerator::VisitProperty(Property* expr) { |
| 2573 Comment cmnt(masm_, "[ Property"); | 2585 Comment cmnt(masm_, "[ Property"); |
| 2574 Expression* key = expr->key(); | 2586 Expression* key = expr->key(); |
| 2575 | 2587 |
| 2576 if (key->IsPropertyName()) { | 2588 if (key->IsPropertyName()) { |
| 2577 VisitForAccumulatorValue(expr->obj()); | 2589 VisitForAccumulatorValue(expr->obj()); |
| 2578 EmitNamedPropertyLoad(expr); | 2590 EmitNamedPropertyLoad(expr); |
| 2579 PrepareForBailoutForId(expr->LoadId(), TOS_REG); | 2591 PrepareForBailoutForId(expr->LoadId(), TOS_REG); |
| 2580 context()->Plug(r0); | 2592 context()->Plug(r0); |
| 2581 } else { | 2593 } else { |
| 2582 VisitForStackValue(expr->obj()); | 2594 VisitForStackValue(expr->obj()); |
| 2583 VisitForAccumulatorValue(expr->key()); | 2595 VisitForAccumulatorValue(expr->key()); |
| 2584 __ pop(r1); | 2596 __ pop(r1); |
| 2585 EmitKeyedPropertyLoad(expr); | 2597 EmitKeyedPropertyLoad(expr); |
| 2586 context()->Plug(r0); | 2598 context()->Plug(r0); |
| 2587 } | 2599 } |
| 2588 } | 2600 } |
| 2589 | 2601 |
| 2590 | 2602 |
| 2591 void FullCodeGenerator::CallIC(Handle<Code> code, | 2603 void FullCodeGenerator::CallIC(Handle<Code> code, |
| 2592 ContextualMode mode, | |
| 2593 TypeFeedbackId ast_id) { | 2604 TypeFeedbackId ast_id) { |
| 2594 ic_total_count_++; | 2605 ic_total_count_++; |
| 2595 // All calls must have a predictable size in full-codegen code to ensure that | 2606 // All calls must have a predictable size in full-codegen code to ensure that |
| 2596 // the debugger can patch them correctly. | 2607 // the debugger can patch them correctly. |
| 2597 ASSERT(mode != CONTEXTUAL || ast_id.IsNone()); | |
| 2598 __ Call(code, RelocInfo::CODE_TARGET, ast_id, al, | 2608 __ Call(code, RelocInfo::CODE_TARGET, ast_id, al, |
| 2599 NEVER_INLINE_TARGET_ADDRESS); | 2609 NEVER_INLINE_TARGET_ADDRESS); |
| 2600 } | 2610 } |
| 2601 | 2611 |
| 2602 void FullCodeGenerator::EmitCallWithIC(Call* expr, | 2612 |
| 2603 Handle<Object> name, | 2613 // Code common for calls using the IC. |
| 2604 ContextualMode mode) { | 2614 void FullCodeGenerator::EmitCallWithIC(Call* expr) { |
| 2605 // Code common for calls using the IC. | 2615 Expression* callee = expr->expression(); |
| 2606 ZoneList<Expression*>* args = expr->arguments(); | 2616 ZoneList<Expression*>* args = expr->arguments(); |
| 2607 int arg_count = args->length(); | 2617 int arg_count = args->length(); |
| 2618 |
| 2619 CallFunctionFlags flags; |
| 2620 // Get the target function. |
| 2621 if (callee->IsVariableProxy()) { |
| 2622 { StackValueContext context(this); |
| 2623 EmitVariableLoad(callee->AsVariableProxy()); |
| 2624 PrepareForBailout(callee, NO_REGISTERS); |
| 2625 } |
| 2626 // Push undefined as receiver. This is patched in the method prologue if it |
| 2627 // is a classic mode method. |
| 2628 __ Push(isolate()->factory()->undefined_value()); |
| 2629 flags = NO_CALL_FUNCTION_FLAGS; |
| 2630 } else { |
| 2631 // Load the function from the receiver. |
| 2632 ASSERT(callee->IsProperty()); |
| 2633 __ ldr(r0, MemOperand(sp, 0)); |
| 2634 EmitNamedPropertyLoad(callee->AsProperty()); |
| 2635 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); |
| 2636 // Push the target function under the receiver. |
| 2637 __ ldr(ip, MemOperand(sp, 0)); |
| 2638 __ push(ip); |
| 2639 __ str(r0, MemOperand(sp, kPointerSize)); |
| 2640 flags = CALL_AS_METHOD; |
| 2641 } |
| 2642 |
| 2643 // Load the arguments. |
| 2608 { PreservePositionScope scope(masm()->positions_recorder()); | 2644 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2609 for (int i = 0; i < arg_count; i++) { | 2645 for (int i = 0; i < arg_count; i++) { |
| 2610 VisitForStackValue(args->at(i)); | 2646 VisitForStackValue(args->at(i)); |
| 2611 } | 2647 } |
| 2612 __ mov(r2, Operand(name)); | |
| 2613 } | 2648 } |
| 2649 |
| 2614 // Record source position for debugger. | 2650 // Record source position for debugger. |
| 2615 SetSourcePosition(expr->position()); | 2651 SetSourcePosition(expr->position()); |
| 2616 // Call the IC initialization code. | 2652 CallFunctionStub stub(arg_count, flags); |
| 2617 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count); | 2653 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 2618 TypeFeedbackId ast_id = mode == CONTEXTUAL | 2654 __ CallStub(&stub); |
| 2619 ? TypeFeedbackId::None() | 2655 |
| 2620 : expr->CallFeedbackId(); | |
| 2621 CallIC(ic, mode, ast_id); | |
| 2622 RecordJSReturnSite(expr); | 2656 RecordJSReturnSite(expr); |
| 2657 |
| 2623 // Restore context register. | 2658 // Restore context register. |
| 2624 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2659 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2625 context()->Plug(r0); | 2660 |
| 2661 context()->DropAndPlug(1, r0); |
| 2626 } | 2662 } |
| 2627 | 2663 |
| 2628 | 2664 |
| 2665 // Code common for calls using the IC. |
| 2629 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | 2666 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 2630 Expression* key) { | 2667 Expression* key) { |
| 2631 // Load the key. | 2668 // Load the key. |
| 2632 VisitForAccumulatorValue(key); | 2669 VisitForAccumulatorValue(key); |
| 2633 | 2670 |
| 2634 // Swap the name of the function and the receiver on the stack to follow | 2671 Expression* callee = expr->expression(); |
| 2635 // the calling convention for call ICs. | |
| 2636 __ pop(r1); | |
| 2637 __ push(r0); | |
| 2638 __ push(r1); | |
| 2639 | |
| 2640 // Code common for calls using the IC. | |
| 2641 ZoneList<Expression*>* args = expr->arguments(); | 2672 ZoneList<Expression*>* args = expr->arguments(); |
| 2642 int arg_count = args->length(); | 2673 int arg_count = args->length(); |
| 2674 |
| 2675 // Load the function from the receiver. |
| 2676 ASSERT(callee->IsProperty()); |
| 2677 __ ldr(r1, MemOperand(sp, 0)); |
| 2678 EmitKeyedPropertyLoad(callee->AsProperty()); |
| 2679 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); |
| 2680 |
| 2681 // Push the target function under the receiver. |
| 2682 __ ldr(ip, MemOperand(sp, 0)); |
| 2683 __ push(ip); |
| 2684 __ str(r0, MemOperand(sp, kPointerSize)); |
| 2685 |
| 2643 { PreservePositionScope scope(masm()->positions_recorder()); | 2686 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2644 for (int i = 0; i < arg_count; i++) { | 2687 for (int i = 0; i < arg_count; i++) { |
| 2645 VisitForStackValue(args->at(i)); | 2688 VisitForStackValue(args->at(i)); |
| 2646 } | 2689 } |
| 2647 } | 2690 } |
| 2691 |
| 2648 // Record source position for debugger. | 2692 // Record source position for debugger. |
| 2649 SetSourcePosition(expr->position()); | 2693 SetSourcePosition(expr->position()); |
| 2650 // Call the IC initialization code. | 2694 CallFunctionStub stub(arg_count, CALL_AS_METHOD); |
| 2651 Handle<Code> ic = | 2695 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 2652 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); | 2696 __ CallStub(&stub); |
| 2653 __ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key. | 2697 |
| 2654 CallIC(ic, NOT_CONTEXTUAL, expr->CallFeedbackId()); | |
| 2655 RecordJSReturnSite(expr); | 2698 RecordJSReturnSite(expr); |
| 2656 // Restore context register. | 2699 // Restore context register. |
| 2657 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2700 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2658 context()->DropAndPlug(1, r0); // Drop the key still on the stack. | 2701 |
| 2702 context()->DropAndPlug(1, r0); |
| 2659 } | 2703 } |
| 2660 | 2704 |
| 2661 | 2705 |
| 2662 void FullCodeGenerator::EmitCallWithStub(Call* expr) { | 2706 void FullCodeGenerator::EmitCallWithStub(Call* expr) { |
| 2663 // Code common for calls using the call stub. | 2707 // Code common for calls using the call stub. |
| 2664 ZoneList<Expression*>* args = expr->arguments(); | 2708 ZoneList<Expression*>* args = expr->arguments(); |
| 2665 int arg_count = args->length(); | 2709 int arg_count = args->length(); |
| 2666 { PreservePositionScope scope(masm()->positions_recorder()); | 2710 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2667 for (int i = 0; i < arg_count; i++) { | 2711 for (int i = 0; i < arg_count; i++) { |
| 2668 VisitForStackValue(args->at(i)); | 2712 VisitForStackValue(args->at(i)); |
| 2669 } | 2713 } |
| 2670 } | 2714 } |
| 2671 // Record source position for debugger. | 2715 // Record source position for debugger. |
| 2672 SetSourcePosition(expr->position()); | 2716 SetSourcePosition(expr->position()); |
| 2673 | 2717 |
| 2674 Handle<Object> uninitialized = | 2718 Handle<Object> uninitialized = |
| 2675 TypeFeedbackCells::UninitializedSentinel(isolate()); | 2719 TypeFeedbackInfo::UninitializedSentinel(isolate()); |
| 2676 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); | 2720 StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized); |
| 2677 RecordTypeFeedbackCell(expr->CallFeedbackId(), cell); | 2721 __ Move(r2, FeedbackVector()); |
| 2678 __ mov(r2, Operand(cell)); | 2722 __ mov(r3, Operand(Smi::FromInt(expr->CallFeedbackSlot()))); |
| 2679 | 2723 |
| 2680 // Record call targets in unoptimized code. | 2724 // Record call targets in unoptimized code. |
| 2681 CallFunctionStub stub(arg_count, RECORD_CALL_TARGET); | 2725 CallFunctionStub stub(arg_count, RECORD_CALL_TARGET); |
| 2682 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); | 2726 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 2683 __ CallStub(&stub, expr->CallFeedbackId()); | 2727 __ CallStub(&stub); |
| 2684 RecordJSReturnSite(expr); | 2728 RecordJSReturnSite(expr); |
| 2685 // Restore context register. | 2729 // Restore context register. |
| 2686 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2730 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2687 context()->DropAndPlug(1, r0); | 2731 context()->DropAndPlug(1, r0); |
| 2688 } | 2732 } |
| 2689 | 2733 |
| 2690 | 2734 |
| 2691 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { | 2735 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { |
| 2692 // r4: copy of the first argument or undefined if it doesn't exist. | 2736 // r4: copy of the first argument or undefined if it doesn't exist. |
| 2693 if (arg_count > 0) { | 2737 if (arg_count > 0) { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2756 // Record source position for debugger. | 2800 // Record source position for debugger. |
| 2757 SetSourcePosition(expr->position()); | 2801 SetSourcePosition(expr->position()); |
| 2758 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); | 2802 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); |
| 2759 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); | 2803 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 2760 __ CallStub(&stub); | 2804 __ CallStub(&stub); |
| 2761 RecordJSReturnSite(expr); | 2805 RecordJSReturnSite(expr); |
| 2762 // Restore context register. | 2806 // Restore context register. |
| 2763 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2807 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2764 context()->DropAndPlug(1, r0); | 2808 context()->DropAndPlug(1, r0); |
| 2765 } else if (call_type == Call::GLOBAL_CALL) { | 2809 } else if (call_type == Call::GLOBAL_CALL) { |
| 2766 // Push global object as receiver for the call IC. | 2810 EmitCallWithIC(expr); |
| 2767 __ ldr(r0, GlobalObjectOperand()); | 2811 |
| 2768 __ push(r0); | |
| 2769 VariableProxy* proxy = callee->AsVariableProxy(); | |
| 2770 EmitCallWithIC(expr, proxy->name(), CONTEXTUAL); | |
| 2771 } else if (call_type == Call::LOOKUP_SLOT_CALL) { | 2812 } else if (call_type == Call::LOOKUP_SLOT_CALL) { |
| 2772 // Call to a lookup slot (dynamically introduced variable). | 2813 // Call to a lookup slot (dynamically introduced variable). |
| 2773 VariableProxy* proxy = callee->AsVariableProxy(); | 2814 VariableProxy* proxy = callee->AsVariableProxy(); |
| 2774 Label slow, done; | 2815 Label slow, done; |
| 2775 | 2816 |
| 2776 { PreservePositionScope scope(masm()->positions_recorder()); | 2817 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2777 // Generate code for loading from variables potentially shadowed | 2818 // Generate code for loading from variables potentially shadowed |
| 2778 // by eval-introduced variables. | 2819 // by eval-introduced variables. |
| 2779 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); | 2820 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); |
| 2780 } | 2821 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2806 | 2847 |
| 2807 // The receiver is either the global receiver or an object found | 2848 // The receiver is either the global receiver or an object found |
| 2808 // by LoadContextSlot. | 2849 // by LoadContextSlot. |
| 2809 EmitCallWithStub(expr); | 2850 EmitCallWithStub(expr); |
| 2810 } else if (call_type == Call::PROPERTY_CALL) { | 2851 } else if (call_type == Call::PROPERTY_CALL) { |
| 2811 Property* property = callee->AsProperty(); | 2852 Property* property = callee->AsProperty(); |
| 2812 { PreservePositionScope scope(masm()->positions_recorder()); | 2853 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2813 VisitForStackValue(property->obj()); | 2854 VisitForStackValue(property->obj()); |
| 2814 } | 2855 } |
| 2815 if (property->key()->IsPropertyName()) { | 2856 if (property->key()->IsPropertyName()) { |
| 2816 EmitCallWithIC(expr, | 2857 EmitCallWithIC(expr); |
| 2817 property->key()->AsLiteral()->value(), | |
| 2818 NOT_CONTEXTUAL); | |
| 2819 } else { | 2858 } else { |
| 2820 EmitKeyedCallWithIC(expr, property->key()); | 2859 EmitKeyedCallWithIC(expr, property->key()); |
| 2821 } | 2860 } |
| 2822 } else { | 2861 } else { |
| 2823 ASSERT(call_type == Call::OTHER_CALL); | 2862 ASSERT(call_type == Call::OTHER_CALL); |
| 2824 // Call to an arbitrary expression not handled specially above. | 2863 // Call to an arbitrary expression not handled specially above. |
| 2825 { PreservePositionScope scope(masm()->positions_recorder()); | 2864 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2826 VisitForStackValue(callee); | 2865 VisitForStackValue(callee); |
| 2827 } | 2866 } |
| 2828 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); | 2867 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2859 // Call the construct call builtin that handles allocation and | 2898 // Call the construct call builtin that handles allocation and |
| 2860 // constructor invocation. | 2899 // constructor invocation. |
| 2861 SetSourcePosition(expr->position()); | 2900 SetSourcePosition(expr->position()); |
| 2862 | 2901 |
| 2863 // Load function and argument count into r1 and r0. | 2902 // Load function and argument count into r1 and r0. |
| 2864 __ mov(r0, Operand(arg_count)); | 2903 __ mov(r0, Operand(arg_count)); |
| 2865 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize)); | 2904 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize)); |
| 2866 | 2905 |
| 2867 // Record call targets in unoptimized code. | 2906 // Record call targets in unoptimized code. |
| 2868 Handle<Object> uninitialized = | 2907 Handle<Object> uninitialized = |
| 2869 TypeFeedbackCells::UninitializedSentinel(isolate()); | 2908 TypeFeedbackInfo::UninitializedSentinel(isolate()); |
| 2870 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); | 2909 StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized); |
| 2871 RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell); | 2910 __ Move(r2, FeedbackVector()); |
| 2872 __ mov(r2, Operand(cell)); | 2911 __ mov(r3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot()))); |
| 2873 | 2912 |
| 2874 CallConstructStub stub(RECORD_CALL_TARGET); | 2913 CallConstructStub stub(RECORD_CALL_TARGET); |
| 2875 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); | 2914 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); |
| 2876 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); | 2915 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); |
| 2877 context()->Plug(r0); | 2916 context()->Plug(r0); |
| 2878 } | 2917 } |
| 2879 | 2918 |
| 2880 | 2919 |
| 2881 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { | 2920 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { |
| 2882 ZoneList<Expression*>* args = expr->arguments(); | 2921 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3449 Register index = r1; | 3488 Register index = r1; |
| 3450 Register value = r2; | 3489 Register value = r2; |
| 3451 | 3490 |
| 3452 VisitForStackValue(args->at(1)); // index | 3491 VisitForStackValue(args->at(1)); // index |
| 3453 VisitForStackValue(args->at(2)); // value | 3492 VisitForStackValue(args->at(2)); // value |
| 3454 VisitForAccumulatorValue(args->at(0)); // string | 3493 VisitForAccumulatorValue(args->at(0)); // string |
| 3455 __ Pop(index, value); | 3494 __ Pop(index, value); |
| 3456 | 3495 |
| 3457 if (FLAG_debug_code) { | 3496 if (FLAG_debug_code) { |
| 3458 __ SmiTst(value); | 3497 __ SmiTst(value); |
| 3459 __ ThrowIf(ne, kNonSmiValue); | 3498 __ Check(eq, kNonSmiValue); |
| 3460 __ SmiTst(index); | 3499 __ SmiTst(index); |
| 3461 __ ThrowIf(ne, kNonSmiIndex); | 3500 __ Check(eq, kNonSmiIndex); |
| 3462 __ SmiUntag(index, index); | 3501 __ SmiUntag(index, index); |
| 3463 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; | 3502 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; |
| 3464 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type); | 3503 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type); |
| 3465 __ SmiTag(index, index); | 3504 __ SmiTag(index, index); |
| 3466 } | 3505 } |
| 3467 | 3506 |
| 3468 __ SmiUntag(value, value); | 3507 __ SmiUntag(value, value); |
| 3469 __ add(ip, | 3508 __ add(ip, |
| 3470 string, | 3509 string, |
| 3471 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | 3510 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag)); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3482 Register index = r1; | 3521 Register index = r1; |
| 3483 Register value = r2; | 3522 Register value = r2; |
| 3484 | 3523 |
| 3485 VisitForStackValue(args->at(1)); // index | 3524 VisitForStackValue(args->at(1)); // index |
| 3486 VisitForStackValue(args->at(2)); // value | 3525 VisitForStackValue(args->at(2)); // value |
| 3487 VisitForAccumulatorValue(args->at(0)); // string | 3526 VisitForAccumulatorValue(args->at(0)); // string |
| 3488 __ Pop(index, value); | 3527 __ Pop(index, value); |
| 3489 | 3528 |
| 3490 if (FLAG_debug_code) { | 3529 if (FLAG_debug_code) { |
| 3491 __ SmiTst(value); | 3530 __ SmiTst(value); |
| 3492 __ ThrowIf(ne, kNonSmiValue); | 3531 __ Check(eq, kNonSmiValue); |
| 3493 __ SmiTst(index); | 3532 __ SmiTst(index); |
| 3494 __ ThrowIf(ne, kNonSmiIndex); | 3533 __ Check(eq, kNonSmiIndex); |
| 3495 __ SmiUntag(index, index); | 3534 __ SmiUntag(index, index); |
| 3496 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; | 3535 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; |
| 3497 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); | 3536 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type); |
| 3498 __ SmiTag(index, index); | 3537 __ SmiTag(index, index); |
| 3499 } | 3538 } |
| 3500 | 3539 |
| 3501 __ SmiUntag(value, value); | 3540 __ SmiUntag(value, value); |
| 3502 __ add(ip, | 3541 __ add(ip, |
| 3503 string, | 3542 string, |
| 3504 Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 3543 Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3667 generator.GenerateSlow(masm_, call_helper); | 3706 generator.GenerateSlow(masm_, call_helper); |
| 3668 | 3707 |
| 3669 __ bind(&done); | 3708 __ bind(&done); |
| 3670 context()->Plug(result); | 3709 context()->Plug(result); |
| 3671 } | 3710 } |
| 3672 | 3711 |
| 3673 | 3712 |
| 3674 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { | 3713 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { |
| 3675 ZoneList<Expression*>* args = expr->arguments(); | 3714 ZoneList<Expression*>* args = expr->arguments(); |
| 3676 ASSERT_EQ(2, args->length()); | 3715 ASSERT_EQ(2, args->length()); |
| 3716 VisitForStackValue(args->at(0)); |
| 3717 VisitForAccumulatorValue(args->at(1)); |
| 3677 | 3718 |
| 3678 if (FLAG_new_string_add) { | 3719 __ pop(r1); |
| 3679 VisitForStackValue(args->at(0)); | 3720 StringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); |
| 3680 VisitForAccumulatorValue(args->at(1)); | 3721 __ CallStub(&stub); |
| 3681 | |
| 3682 __ pop(r1); | |
| 3683 NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); | |
| 3684 __ CallStub(&stub); | |
| 3685 } else { | |
| 3686 VisitForStackValue(args->at(0)); | |
| 3687 VisitForStackValue(args->at(1)); | |
| 3688 | |
| 3689 StringAddStub stub(STRING_ADD_CHECK_BOTH); | |
| 3690 __ CallStub(&stub); | |
| 3691 } | |
| 3692 context()->Plug(r0); | 3722 context()->Plug(r0); |
| 3693 } | 3723 } |
| 3694 | 3724 |
| 3695 | 3725 |
| 3696 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { | 3726 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { |
| 3697 ZoneList<Expression*>* args = expr->arguments(); | 3727 ZoneList<Expression*>* args = expr->arguments(); |
| 3698 ASSERT_EQ(2, args->length()); | 3728 ASSERT_EQ(2, args->length()); |
| 3699 VisitForStackValue(args->at(0)); | 3729 VisitForStackValue(args->at(0)); |
| 3700 VisitForStackValue(args->at(1)); | 3730 VisitForStackValue(args->at(1)); |
| 3701 | 3731 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3756 context()->Plug(r0); | 3786 context()->Plug(r0); |
| 3757 } | 3787 } |
| 3758 | 3788 |
| 3759 | 3789 |
| 3760 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { | 3790 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { |
| 3761 RegExpConstructResultStub stub; | 3791 RegExpConstructResultStub stub; |
| 3762 ZoneList<Expression*>* args = expr->arguments(); | 3792 ZoneList<Expression*>* args = expr->arguments(); |
| 3763 ASSERT(args->length() == 3); | 3793 ASSERT(args->length() == 3); |
| 3764 VisitForStackValue(args->at(0)); | 3794 VisitForStackValue(args->at(0)); |
| 3765 VisitForStackValue(args->at(1)); | 3795 VisitForStackValue(args->at(1)); |
| 3766 VisitForStackValue(args->at(2)); | 3796 VisitForAccumulatorValue(args->at(2)); |
| 3797 __ pop(r1); |
| 3798 __ pop(r2); |
| 3767 __ CallStub(&stub); | 3799 __ CallStub(&stub); |
| 3768 context()->Plug(r0); | 3800 context()->Plug(r0); |
| 3769 } | 3801 } |
| 3770 | 3802 |
| 3771 | 3803 |
| 3772 void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { | 3804 void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { |
| 3773 ZoneList<Expression*>* args = expr->arguments(); | 3805 ZoneList<Expression*>* args = expr->arguments(); |
| 3774 ASSERT_EQ(2, args->length()); | 3806 ASSERT_EQ(2, args->length()); |
| 3775 ASSERT_NE(NULL, args->at(0)->AsLiteral()); | 3807 ASSERT_NE(NULL, args->at(0)->AsLiteral()); |
| 3776 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value(); | 3808 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value(); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3789 Register key = r0; | 3821 Register key = r0; |
| 3790 Register cache = r1; | 3822 Register cache = r1; |
| 3791 __ ldr(cache, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); | 3823 __ ldr(cache, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); |
| 3792 __ ldr(cache, FieldMemOperand(cache, GlobalObject::kNativeContextOffset)); | 3824 __ ldr(cache, FieldMemOperand(cache, GlobalObject::kNativeContextOffset)); |
| 3793 __ ldr(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); | 3825 __ ldr(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX)); |
| 3794 __ ldr(cache, | 3826 __ ldr(cache, |
| 3795 FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); | 3827 FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id))); |
| 3796 | 3828 |
| 3797 | 3829 |
| 3798 Label done, not_found; | 3830 Label done, not_found; |
| 3799 // tmp now holds finger offset as a smi. | |
| 3800 __ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset)); | 3831 __ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset)); |
| 3801 // r2 now holds finger offset as a smi. | 3832 // r2 now holds finger offset as a smi. |
| 3802 __ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); | 3833 __ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
| 3803 // r3 now points to the start of fixed array elements. | 3834 // r3 now points to the start of fixed array elements. |
| 3804 __ ldr(r2, MemOperand::PointerAddressFromSmiKey(r3, r2, PreIndex)); | 3835 __ ldr(r2, MemOperand::PointerAddressFromSmiKey(r3, r2, PreIndex)); |
| 3805 // Note side effect of PreIndex: r3 now points to the key of the pair. | 3836 // Note side effect of PreIndex: r3 now points to the key of the pair. |
| 3806 __ cmp(key, r2); | 3837 __ cmp(key, r2); |
| 3807 __ b(ne, ¬_found); | 3838 __ b(ne, ¬_found); |
| 3808 | 3839 |
| 3809 __ ldr(r0, MemOperand(r3, kPointerSize)); | 3840 __ ldr(r0, MemOperand(r3, kPointerSize)); |
| 3810 __ b(&done); | 3841 __ b(&done); |
| 3811 | 3842 |
| 3812 __ bind(¬_found); | 3843 __ bind(¬_found); |
| 3813 // Call runtime to perform the lookup. | 3844 // Call runtime to perform the lookup. |
| 3814 __ Push(cache, key); | 3845 __ Push(cache, key); |
| 3815 __ CallRuntime(Runtime::kGetFromCache, 2); | 3846 __ CallRuntime(Runtime::kGetFromCache, 2); |
| 3816 | 3847 |
| 3817 __ bind(&done); | 3848 __ bind(&done); |
| 3818 context()->Plug(r0); | 3849 context()->Plug(r0); |
| 3819 } | 3850 } |
| 3820 | 3851 |
| 3821 | 3852 |
| 3822 void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) { | |
| 3823 ZoneList<Expression*>* args = expr->arguments(); | |
| 3824 ASSERT_EQ(2, args->length()); | |
| 3825 | |
| 3826 Register right = r0; | |
| 3827 Register left = r1; | |
| 3828 Register tmp = r2; | |
| 3829 Register tmp2 = r3; | |
| 3830 | |
| 3831 VisitForStackValue(args->at(0)); | |
| 3832 VisitForAccumulatorValue(args->at(1)); | |
| 3833 __ pop(left); | |
| 3834 | |
| 3835 Label done, fail, ok; | |
| 3836 __ cmp(left, Operand(right)); | |
| 3837 __ b(eq, &ok); | |
| 3838 // Fail if either is a non-HeapObject. | |
| 3839 __ and_(tmp, left, Operand(right)); | |
| 3840 __ JumpIfSmi(tmp, &fail); | |
| 3841 __ ldr(tmp, FieldMemOperand(left, HeapObject::kMapOffset)); | |
| 3842 __ ldrb(tmp2, FieldMemOperand(tmp, Map::kInstanceTypeOffset)); | |
| 3843 __ cmp(tmp2, Operand(JS_REGEXP_TYPE)); | |
| 3844 __ b(ne, &fail); | |
| 3845 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | |
| 3846 __ cmp(tmp, Operand(tmp2)); | |
| 3847 __ b(ne, &fail); | |
| 3848 __ ldr(tmp, FieldMemOperand(left, JSRegExp::kDataOffset)); | |
| 3849 __ ldr(tmp2, FieldMemOperand(right, JSRegExp::kDataOffset)); | |
| 3850 __ cmp(tmp, tmp2); | |
| 3851 __ b(eq, &ok); | |
| 3852 __ bind(&fail); | |
| 3853 __ LoadRoot(r0, Heap::kFalseValueRootIndex); | |
| 3854 __ jmp(&done); | |
| 3855 __ bind(&ok); | |
| 3856 __ LoadRoot(r0, Heap::kTrueValueRootIndex); | |
| 3857 __ bind(&done); | |
| 3858 | |
| 3859 context()->Plug(r0); | |
| 3860 } | |
| 3861 | |
| 3862 | |
| 3863 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { | 3853 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { |
| 3864 ZoneList<Expression*>* args = expr->arguments(); | 3854 ZoneList<Expression*>* args = expr->arguments(); |
| 3865 VisitForAccumulatorValue(args->at(0)); | 3855 VisitForAccumulatorValue(args->at(0)); |
| 3866 | 3856 |
| 3867 Label materialize_true, materialize_false; | 3857 Label materialize_true, materialize_false; |
| 3868 Label* if_true = NULL; | 3858 Label* if_true = NULL; |
| 3869 Label* if_false = NULL; | 3859 Label* if_false = NULL; |
| 3870 Label* fall_through = NULL; | 3860 Label* fall_through = NULL; |
| 3871 context()->PrepareTest(&materialize_true, &materialize_false, | 3861 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3872 &if_true, &if_false, &fall_through); | 3862 &if_true, &if_false, &fall_through); |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4132 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 4122 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 4133 Handle<String> name = expr->name(); | 4123 Handle<String> name = expr->name(); |
| 4134 if (name->length() > 0 && name->Get(0) == '_') { | 4124 if (name->length() > 0 && name->Get(0) == '_') { |
| 4135 Comment cmnt(masm_, "[ InlineRuntimeCall"); | 4125 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
| 4136 EmitInlineRuntimeCall(expr); | 4126 EmitInlineRuntimeCall(expr); |
| 4137 return; | 4127 return; |
| 4138 } | 4128 } |
| 4139 | 4129 |
| 4140 Comment cmnt(masm_, "[ CallRuntime"); | 4130 Comment cmnt(masm_, "[ CallRuntime"); |
| 4141 ZoneList<Expression*>* args = expr->arguments(); | 4131 ZoneList<Expression*>* args = expr->arguments(); |
| 4132 int arg_count = args->length(); |
| 4142 | 4133 |
| 4143 if (expr->is_jsruntime()) { | 4134 if (expr->is_jsruntime()) { |
| 4144 // Prepare for calling JS runtime function. | 4135 // Push the builtins object as the receiver. |
| 4145 __ ldr(r0, GlobalObjectOperand()); | 4136 __ ldr(r0, GlobalObjectOperand()); |
| 4146 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset)); | 4137 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset)); |
| 4147 __ push(r0); | 4138 __ push(r0); |
| 4148 } | |
| 4149 | 4139 |
| 4150 // Push the arguments ("left-to-right"). | 4140 // Load the function from the receiver. |
| 4151 int arg_count = args->length(); | 4141 __ mov(r2, Operand(expr->name())); |
| 4152 for (int i = 0; i < arg_count; i++) { | 4142 CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); |
| 4153 VisitForStackValue(args->at(i)); | |
| 4154 } | |
| 4155 | 4143 |
| 4156 if (expr->is_jsruntime()) { | 4144 // Push the target function under the receiver. |
| 4157 // Call the JS runtime function. | 4145 __ ldr(ip, MemOperand(sp, 0)); |
| 4158 __ mov(r2, Operand(expr->name())); | 4146 __ push(ip); |
| 4159 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count); | 4147 __ str(r0, MemOperand(sp, kPointerSize)); |
| 4160 CallIC(ic, NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); | 4148 |
| 4149 // Push the arguments ("left-to-right"). |
| 4150 int arg_count = args->length(); |
| 4151 for (int i = 0; i < arg_count; i++) { |
| 4152 VisitForStackValue(args->at(i)); |
| 4153 } |
| 4154 |
| 4155 // Record source position of the IC call. |
| 4156 SetSourcePosition(expr->position()); |
| 4157 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); |
| 4158 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 4159 __ CallStub(&stub); |
| 4160 |
| 4161 // Restore context register. | 4161 // Restore context register. |
| 4162 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 4162 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 4163 |
| 4164 context()->DropAndPlug(1, r0); |
| 4163 } else { | 4165 } else { |
| 4166 // Push the arguments ("left-to-right"). |
| 4167 for (int i = 0; i < arg_count; i++) { |
| 4168 VisitForStackValue(args->at(i)); |
| 4169 } |
| 4170 |
| 4164 // Call the C runtime function. | 4171 // Call the C runtime function. |
| 4165 __ CallRuntime(expr->function(), arg_count); | 4172 __ CallRuntime(expr->function(), arg_count); |
| 4173 context()->Plug(r0); |
| 4166 } | 4174 } |
| 4167 context()->Plug(r0); | |
| 4168 } | 4175 } |
| 4169 | 4176 |
| 4170 | 4177 |
| 4171 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 4178 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 4172 switch (expr->op()) { | 4179 switch (expr->op()) { |
| 4173 case Token::DELETE: { | 4180 case Token::DELETE: { |
| 4174 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 4181 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
| 4175 Property* property = expr->expression()->AsProperty(); | 4182 Property* property = expr->expression()->AsProperty(); |
| 4176 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 4183 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
| 4177 | 4184 |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4397 | 4404 |
| 4398 | 4405 |
| 4399 __ bind(&stub_call); | 4406 __ bind(&stub_call); |
| 4400 __ mov(r1, r0); | 4407 __ mov(r1, r0); |
| 4401 __ mov(r0, Operand(Smi::FromInt(count_value))); | 4408 __ mov(r0, Operand(Smi::FromInt(count_value))); |
| 4402 | 4409 |
| 4403 // Record position before stub call. | 4410 // Record position before stub call. |
| 4404 SetSourcePosition(expr->position()); | 4411 SetSourcePosition(expr->position()); |
| 4405 | 4412 |
| 4406 BinaryOpICStub stub(Token::ADD, NO_OVERWRITE); | 4413 BinaryOpICStub stub(Token::ADD, NO_OVERWRITE); |
| 4407 CallIC(stub.GetCode(isolate()), | 4414 CallIC(stub.GetCode(isolate()), expr->CountBinOpFeedbackId()); |
| 4408 NOT_CONTEXTUAL, | |
| 4409 expr->CountBinOpFeedbackId()); | |
| 4410 patch_site.EmitPatchInfo(); | 4415 patch_site.EmitPatchInfo(); |
| 4411 __ bind(&done); | 4416 __ bind(&done); |
| 4412 | 4417 |
| 4413 // Store the value returned in r0. | 4418 // Store the value returned in r0. |
| 4414 switch (assign_type) { | 4419 switch (assign_type) { |
| 4415 case VARIABLE: | 4420 case VARIABLE: |
| 4416 if (expr->is_postfix()) { | 4421 if (expr->is_postfix()) { |
| 4417 { EffectContext context(this); | 4422 { EffectContext context(this); |
| 4418 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 4423 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 4419 Token::ASSIGN); | 4424 Token::ASSIGN); |
| 4420 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4425 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4421 context.Plug(r0); | 4426 context.Plug(r0); |
| 4422 } | 4427 } |
| 4423 // For all contexts except EffectConstant We have the result on | 4428 // For all contexts except EffectConstant We have the result on |
| 4424 // top of the stack. | 4429 // top of the stack. |
| 4425 if (!context()->IsEffect()) { | 4430 if (!context()->IsEffect()) { |
| 4426 context()->PlugTOS(); | 4431 context()->PlugTOS(); |
| 4427 } | 4432 } |
| 4428 } else { | 4433 } else { |
| 4429 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 4434 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 4430 Token::ASSIGN); | 4435 Token::ASSIGN); |
| 4431 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4436 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4432 context()->Plug(r0); | 4437 context()->Plug(r0); |
| 4433 } | 4438 } |
| 4434 break; | 4439 break; |
| 4435 case NAMED_PROPERTY: { | 4440 case NAMED_PROPERTY: { |
| 4436 __ mov(r2, Operand(prop->key()->AsLiteral()->value())); | 4441 __ mov(r2, Operand(prop->key()->AsLiteral()->value())); |
| 4437 __ pop(r1); | 4442 __ pop(r1); |
| 4438 CallStoreIC(NOT_CONTEXTUAL, expr->CountStoreFeedbackId()); | 4443 CallStoreIC(expr->CountStoreFeedbackId()); |
| 4439 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4444 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4440 if (expr->is_postfix()) { | 4445 if (expr->is_postfix()) { |
| 4441 if (!context()->IsEffect()) { | 4446 if (!context()->IsEffect()) { |
| 4442 context()->PlugTOS(); | 4447 context()->PlugTOS(); |
| 4443 } | 4448 } |
| 4444 } else { | 4449 } else { |
| 4445 context()->Plug(r0); | 4450 context()->Plug(r0); |
| 4446 } | 4451 } |
| 4447 break; | 4452 break; |
| 4448 } | 4453 } |
| 4449 case KEYED_PROPERTY: { | 4454 case KEYED_PROPERTY: { |
| 4450 __ Pop(r2, r1); // r1 = key. r2 = receiver. | 4455 __ Pop(r2, r1); // r1 = key. r2 = receiver. |
| 4451 Handle<Code> ic = is_classic_mode() | 4456 Handle<Code> ic = is_classic_mode() |
| 4452 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 4457 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 4453 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 4458 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 4454 CallIC(ic, NOT_CONTEXTUAL, expr->CountStoreFeedbackId()); | 4459 CallIC(ic, expr->CountStoreFeedbackId()); |
| 4455 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4460 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4456 if (expr->is_postfix()) { | 4461 if (expr->is_postfix()) { |
| 4457 if (!context()->IsEffect()) { | 4462 if (!context()->IsEffect()) { |
| 4458 context()->PlugTOS(); | 4463 context()->PlugTOS(); |
| 4459 } | 4464 } |
| 4460 } else { | 4465 } else { |
| 4461 context()->Plug(r0); | 4466 context()->Plug(r0); |
| 4462 } | 4467 } |
| 4463 break; | 4468 break; |
| 4464 } | 4469 } |
| 4465 } | 4470 } |
| 4466 } | 4471 } |
| 4467 | 4472 |
| 4468 | 4473 |
| 4469 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 4474 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 4470 ASSERT(!context()->IsEffect()); | 4475 ASSERT(!context()->IsEffect()); |
| 4471 ASSERT(!context()->IsTest()); | 4476 ASSERT(!context()->IsTest()); |
| 4472 VariableProxy* proxy = expr->AsVariableProxy(); | 4477 VariableProxy* proxy = expr->AsVariableProxy(); |
| 4473 if (proxy != NULL && proxy->var()->IsUnallocated()) { | 4478 if (proxy != NULL && proxy->var()->IsUnallocated()) { |
| 4474 Comment cmnt(masm_, "Global variable"); | 4479 Comment cmnt(masm_, "[ Global variable"); |
| 4475 __ ldr(r0, GlobalObjectOperand()); | 4480 __ ldr(r0, GlobalObjectOperand()); |
| 4476 __ mov(r2, Operand(proxy->name())); | 4481 __ mov(r2, Operand(proxy->name())); |
| 4477 // Use a regular load, not a contextual load, to avoid a reference | 4482 // Use a regular load, not a contextual load, to avoid a reference |
| 4478 // error. | 4483 // error. |
| 4479 CallLoadIC(NOT_CONTEXTUAL); | 4484 CallLoadIC(NOT_CONTEXTUAL); |
| 4480 PrepareForBailout(expr, TOS_REG); | 4485 PrepareForBailout(expr, TOS_REG); |
| 4481 context()->Plug(r0); | 4486 context()->Plug(r0); |
| 4482 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { | 4487 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { |
| 4488 Comment cmnt(masm_, "[ Lookup slot"); |
| 4483 Label done, slow; | 4489 Label done, slow; |
| 4484 | 4490 |
| 4485 // Generate code for loading from variables potentially shadowed | 4491 // Generate code for loading from variables potentially shadowed |
| 4486 // by eval-introduced variables. | 4492 // by eval-introduced variables. |
| 4487 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); | 4493 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); |
| 4488 | 4494 |
| 4489 __ bind(&slow); | 4495 __ bind(&slow); |
| 4490 __ mov(r0, Operand(proxy->name())); | 4496 __ mov(r0, Operand(proxy->name())); |
| 4491 __ Push(cp, r0); | 4497 __ Push(cp, r0); |
| 4492 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 4498 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4634 __ orr(r2, r0, Operand(r1)); | 4640 __ orr(r2, r0, Operand(r1)); |
| 4635 patch_site.EmitJumpIfNotSmi(r2, &slow_case); | 4641 patch_site.EmitJumpIfNotSmi(r2, &slow_case); |
| 4636 __ cmp(r1, r0); | 4642 __ cmp(r1, r0); |
| 4637 Split(cond, if_true, if_false, NULL); | 4643 Split(cond, if_true, if_false, NULL); |
| 4638 __ bind(&slow_case); | 4644 __ bind(&slow_case); |
| 4639 } | 4645 } |
| 4640 | 4646 |
| 4641 // Record position and call the compare IC. | 4647 // Record position and call the compare IC. |
| 4642 SetSourcePosition(expr->position()); | 4648 SetSourcePosition(expr->position()); |
| 4643 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); | 4649 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); |
| 4644 CallIC(ic, NOT_CONTEXTUAL, expr->CompareOperationFeedbackId()); | 4650 CallIC(ic, expr->CompareOperationFeedbackId()); |
| 4645 patch_site.EmitPatchInfo(); | 4651 patch_site.EmitPatchInfo(); |
| 4646 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 4652 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 4647 __ cmp(r0, Operand::Zero()); | 4653 __ cmp(r0, Operand::Zero()); |
| 4648 Split(cond, if_true, if_false, fall_through); | 4654 Split(cond, if_true, if_false, fall_through); |
| 4649 } | 4655 } |
| 4650 } | 4656 } |
| 4651 | 4657 |
| 4652 // Convert the result of the comparison into one expected for this | 4658 // Convert the result of the comparison into one expected for this |
| 4653 // expression's context. | 4659 // expression's context. |
| 4654 context()->Plug(if_true, if_false); | 4660 context()->Plug(if_true, if_false); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 4669 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 4675 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 4670 if (expr->op() == Token::EQ_STRICT) { | 4676 if (expr->op() == Token::EQ_STRICT) { |
| 4671 Heap::RootListIndex nil_value = nil == kNullValue ? | 4677 Heap::RootListIndex nil_value = nil == kNullValue ? |
| 4672 Heap::kNullValueRootIndex : | 4678 Heap::kNullValueRootIndex : |
| 4673 Heap::kUndefinedValueRootIndex; | 4679 Heap::kUndefinedValueRootIndex; |
| 4674 __ LoadRoot(r1, nil_value); | 4680 __ LoadRoot(r1, nil_value); |
| 4675 __ cmp(r0, r1); | 4681 __ cmp(r0, r1); |
| 4676 Split(eq, if_true, if_false, fall_through); | 4682 Split(eq, if_true, if_false, fall_through); |
| 4677 } else { | 4683 } else { |
| 4678 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); | 4684 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); |
| 4679 CallIC(ic, NOT_CONTEXTUAL, expr->CompareOperationFeedbackId()); | 4685 CallIC(ic, expr->CompareOperationFeedbackId()); |
| 4680 __ cmp(r0, Operand(0)); | 4686 __ cmp(r0, Operand(0)); |
| 4681 Split(ne, if_true, if_false, fall_through); | 4687 Split(ne, if_true, if_false, fall_through); |
| 4682 } | 4688 } |
| 4683 context()->Plug(if_true, if_false); | 4689 context()->Plug(if_true, if_false); |
| 4684 } | 4690 } |
| 4685 | 4691 |
| 4686 | 4692 |
| 4687 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 4693 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
| 4688 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 4694 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4689 context()->Plug(r0); | 4695 context()->Plug(r0); |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4912 ASSERT(Memory::uint32_at(interrupt_address_pointer) == | 4918 ASSERT(Memory::uint32_at(interrupt_address_pointer) == |
| 4913 reinterpret_cast<uint32_t>( | 4919 reinterpret_cast<uint32_t>( |
| 4914 isolate->builtins()->OsrAfterStackCheck()->entry())); | 4920 isolate->builtins()->OsrAfterStackCheck()->entry())); |
| 4915 return OSR_AFTER_STACK_CHECK; | 4921 return OSR_AFTER_STACK_CHECK; |
| 4916 } | 4922 } |
| 4917 | 4923 |
| 4918 | 4924 |
| 4919 } } // namespace v8::internal | 4925 } } // namespace v8::internal |
| 4920 | 4926 |
| 4921 #endif // V8_TARGET_ARCH_ARM | 4927 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |