| 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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 } | 77 } |
| 78 | 78 |
| 79 // When initially emitting this ensure that a jump is always generated to skip | 79 // When initially emitting this ensure that a jump is always generated to skip |
| 80 // the inlined smi code. | 80 // the inlined smi code. |
| 81 void EmitJumpIfNotSmi(Register reg, Label* target) { | 81 void EmitJumpIfNotSmi(Register reg, Label* target) { |
| 82 ASSERT(!patch_site_.is_bound() && !info_emitted_); | 82 ASSERT(!patch_site_.is_bound() && !info_emitted_); |
| 83 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | 83 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); |
| 84 __ bind(&patch_site_); | 84 __ bind(&patch_site_); |
| 85 __ andi(at, reg, 0); | 85 __ andi(at, reg, 0); |
| 86 // Always taken before patched. | 86 // Always taken before patched. |
| 87 __ Branch(target, eq, at, Operand(zero_reg)); | 87 __ BranchShort(target, eq, at, Operand(zero_reg)); |
| 88 } | 88 } |
| 89 | 89 |
| 90 // When initially emitting this ensure that a jump is never generated to skip | 90 // When initially emitting this ensure that a jump is never generated to skip |
| 91 // the inlined smi code. | 91 // the inlined smi code. |
| 92 void EmitJumpIfSmi(Register reg, Label* target) { | 92 void EmitJumpIfSmi(Register reg, Label* target) { |
| 93 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); | 93 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_); |
| 94 ASSERT(!patch_site_.is_bound() && !info_emitted_); | 94 ASSERT(!patch_site_.is_bound() && !info_emitted_); |
| 95 __ bind(&patch_site_); | 95 __ bind(&patch_site_); |
| 96 __ andi(at, reg, 0); | 96 __ andi(at, reg, 0); |
| 97 // Never taken before patched. | 97 // Never taken before patched. |
| 98 __ Branch(target, ne, at, Operand(zero_reg)); | 98 __ BranchShort(target, ne, at, Operand(zero_reg)); |
| 99 } | 99 } |
| 100 | 100 |
| 101 void EmitPatchInfo() { | 101 void EmitPatchInfo() { |
| 102 if (patch_site_.is_bound()) { | 102 if (patch_site_.is_bound()) { |
| 103 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_); | 103 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_); |
| 104 Register reg = Register::from_code(delta_to_patch_site / kImm16Mask); | 104 Register reg = Register::from_code(delta_to_patch_site / kImm16Mask); |
| 105 __ andi(zero_reg, reg, delta_to_patch_site % kImm16Mask); | 105 __ andi(zero_reg, reg, delta_to_patch_site % kImm16Mask); |
| 106 #ifdef DEBUG | 106 #ifdef DEBUG |
| 107 info_emitted_ = true; | 107 info_emitted_ = true; |
| 108 #endif | 108 #endif |
| (...skipping 22 matching lines...) Expand all Loading... |
| 131 // o fp: our caller's frame pointer | 131 // o fp: our caller's frame pointer |
| 132 // o sp: stack pointer | 132 // o sp: stack pointer |
| 133 // o ra: return address | 133 // o ra: return address |
| 134 // | 134 // |
| 135 // The function builds a JS frame. Please see JavaScriptFrameConstants in | 135 // The function builds a JS frame. Please see JavaScriptFrameConstants in |
| 136 // frames-mips.h for its layout. | 136 // frames-mips.h for its layout. |
| 137 void FullCodeGenerator::Generate() { | 137 void FullCodeGenerator::Generate() { |
| 138 CompilationInfo* info = info_; | 138 CompilationInfo* info = info_; |
| 139 handler_table_ = | 139 handler_table_ = |
| 140 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); | 140 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED); |
| 141 |
| 142 InitializeFeedbackVector(); |
| 143 |
| 141 profiling_counter_ = isolate()->factory()->NewCell( | 144 profiling_counter_ = isolate()->factory()->NewCell( |
| 142 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); | 145 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate())); |
| 143 SetFunctionPosition(function()); | 146 SetFunctionPosition(function()); |
| 144 Comment cmnt(masm_, "[ function compiled by full code generator"); | 147 Comment cmnt(masm_, "[ function compiled by full code generator"); |
| 145 | 148 |
| 146 ProfileEntryHookStub::MaybeCallEntryHook(masm_); | 149 ProfileEntryHookStub::MaybeCallEntryHook(masm_); |
| 147 | 150 |
| 148 #ifdef DEBUG | 151 #ifdef DEBUG |
| 149 if (strlen(FLAG_stop_at) > 0 && | 152 if (strlen(FLAG_stop_at) > 0 && |
| 150 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { | 153 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 } | 207 } |
| 205 } | 208 } |
| 206 | 209 |
| 207 bool function_in_register = true; | 210 bool function_in_register = true; |
| 208 | 211 |
| 209 // Possibly allocate a local context. | 212 // Possibly allocate a local context. |
| 210 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; | 213 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
| 211 if (heap_slots > 0) { | 214 if (heap_slots > 0) { |
| 212 Comment cmnt(masm_, "[ Allocate context"); | 215 Comment cmnt(masm_, "[ Allocate context"); |
| 213 // Argument to NewContext is the function, which is still in a1. | 216 // Argument to NewContext is the function, which is still in a1. |
| 214 __ push(a1); | |
| 215 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) { | 217 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) { |
| 218 __ push(a1); |
| 216 __ Push(info->scope()->GetScopeInfo()); | 219 __ Push(info->scope()->GetScopeInfo()); |
| 217 __ CallRuntime(Runtime::kNewGlobalContext, 2); | 220 __ CallRuntime(Runtime::kNewGlobalContext, 2); |
| 218 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 221 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
| 219 FastNewContextStub stub(heap_slots); | 222 FastNewContextStub stub(heap_slots); |
| 220 __ CallStub(&stub); | 223 __ CallStub(&stub); |
| 221 } else { | 224 } else { |
| 225 __ push(a1); |
| 222 __ CallRuntime(Runtime::kNewFunctionContext, 1); | 226 __ CallRuntime(Runtime::kNewFunctionContext, 1); |
| 223 } | 227 } |
| 224 function_in_register = false; | 228 function_in_register = false; |
| 225 // Context is returned in both v0 and cp. It replaces the context | 229 // Context is returned in v0. It replaces the context passed to us. |
| 226 // passed to us. It's saved in the stack and kept live in cp. | 230 // It's saved in the stack and kept live in cp. |
| 227 __ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 231 __ mov(cp, v0); |
| 232 __ sw(v0, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 228 // Copy any necessary parameters into the context. | 233 // Copy any necessary parameters into the context. |
| 229 int num_parameters = info->scope()->num_parameters(); | 234 int num_parameters = info->scope()->num_parameters(); |
| 230 for (int i = 0; i < num_parameters; i++) { | 235 for (int i = 0; i < num_parameters; i++) { |
| 231 Variable* var = scope()->parameter(i); | 236 Variable* var = scope()->parameter(i); |
| 232 if (var->IsContextSlot()) { | 237 if (var->IsContextSlot()) { |
| 233 int parameter_offset = StandardFrameConstants::kCallerSPOffset + | 238 int parameter_offset = StandardFrameConstants::kCallerSPOffset + |
| 234 (num_parameters - 1 - i) * kPointerSize; | 239 (num_parameters - 1 - i) * kPointerSize; |
| 235 // Load parameter from stack. | 240 // Load parameter from stack. |
| 236 __ lw(a0, MemOperand(fp, parameter_offset)); | 241 __ lw(a0, MemOperand(fp, parameter_offset)); |
| 237 // Store it in the context. | 242 // Store it in the context. |
| (...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 670 } | 675 } |
| 671 } | 676 } |
| 672 | 677 |
| 673 | 678 |
| 674 void FullCodeGenerator::DoTest(Expression* condition, | 679 void FullCodeGenerator::DoTest(Expression* condition, |
| 675 Label* if_true, | 680 Label* if_true, |
| 676 Label* if_false, | 681 Label* if_false, |
| 677 Label* fall_through) { | 682 Label* fall_through) { |
| 678 __ mov(a0, result_register()); | 683 __ mov(a0, result_register()); |
| 679 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); | 684 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate()); |
| 680 CallIC(ic, NOT_CONTEXTUAL, condition->test_id()); | 685 CallIC(ic, condition->test_id()); |
| 681 __ mov(at, zero_reg); | 686 __ mov(at, zero_reg); |
| 682 Split(ne, v0, Operand(at), if_true, if_false, fall_through); | 687 Split(ne, v0, Operand(at), if_true, if_false, fall_through); |
| 683 } | 688 } |
| 684 | 689 |
| 685 | 690 |
| 686 void FullCodeGenerator::Split(Condition cc, | 691 void FullCodeGenerator::Split(Condition cc, |
| 687 Register lhs, | 692 Register lhs, |
| 688 const Operand& rhs, | 693 const Operand& rhs, |
| 689 Label* if_true, | 694 Label* if_true, |
| 690 Label* if_false, | 695 Label* if_false, |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1035 __ Branch(&next_test, ne, a1, Operand(a0)); | 1040 __ Branch(&next_test, ne, a1, Operand(a0)); |
| 1036 __ Drop(1); // Switch value is no longer needed. | 1041 __ Drop(1); // Switch value is no longer needed. |
| 1037 __ Branch(clause->body_target()); | 1042 __ Branch(clause->body_target()); |
| 1038 | 1043 |
| 1039 __ bind(&slow_case); | 1044 __ bind(&slow_case); |
| 1040 } | 1045 } |
| 1041 | 1046 |
| 1042 // Record position before stub call for type feedback. | 1047 // Record position before stub call for type feedback. |
| 1043 SetSourcePosition(clause->position()); | 1048 SetSourcePosition(clause->position()); |
| 1044 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); | 1049 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT); |
| 1045 CallIC(ic, NOT_CONTEXTUAL, clause->CompareId()); | 1050 CallIC(ic, clause->CompareId()); |
| 1046 patch_site.EmitPatchInfo(); | 1051 patch_site.EmitPatchInfo(); |
| 1047 | 1052 |
| 1048 Label skip; | 1053 Label skip; |
| 1049 __ Branch(&skip); | 1054 __ Branch(&skip); |
| 1050 PrepareForBailout(clause, TOS_REG); | 1055 PrepareForBailout(clause, TOS_REG); |
| 1051 __ LoadRoot(at, Heap::kTrueValueRootIndex); | 1056 __ LoadRoot(at, Heap::kTrueValueRootIndex); |
| 1052 __ Branch(&next_test, ne, v0, Operand(at)); | 1057 __ Branch(&next_test, ne, v0, Operand(at)); |
| 1053 __ Drop(1); | 1058 __ Drop(1); |
| 1054 __ Branch(clause->body_target()); | 1059 __ Branch(clause->body_target()); |
| 1055 __ bind(&skip); | 1060 __ bind(&skip); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1078 VisitStatements(clause->statements()); | 1083 VisitStatements(clause->statements()); |
| 1079 } | 1084 } |
| 1080 | 1085 |
| 1081 __ bind(nested_statement.break_label()); | 1086 __ bind(nested_statement.break_label()); |
| 1082 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); | 1087 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS); |
| 1083 } | 1088 } |
| 1084 | 1089 |
| 1085 | 1090 |
| 1086 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { | 1091 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
| 1087 Comment cmnt(masm_, "[ ForInStatement"); | 1092 Comment cmnt(masm_, "[ ForInStatement"); |
| 1093 int slot = stmt->ForInFeedbackSlot(); |
| 1088 SetStatementPosition(stmt); | 1094 SetStatementPosition(stmt); |
| 1089 | 1095 |
| 1090 Label loop, exit; | 1096 Label loop, exit; |
| 1091 ForIn loop_statement(this, stmt); | 1097 ForIn loop_statement(this, stmt); |
| 1092 increment_loop_depth(); | 1098 increment_loop_depth(); |
| 1093 | 1099 |
| 1094 // Get the object to enumerate over. If the object is null or undefined, skip | 1100 // Get the object to enumerate over. If the object is null or undefined, skip |
| 1095 // over the loop. See ECMA-262 version 5, section 12.6.4. | 1101 // over the loop. See ECMA-262 version 5, section 12.6.4. |
| 1096 VisitForAccumulatorValue(stmt->enumerable()); | 1102 VisitForAccumulatorValue(stmt->enumerable()); |
| 1097 __ mov(a0, result_register()); // Result as param to InvokeBuiltin below. | 1103 __ mov(a0, result_register()); // Result as param to InvokeBuiltin below. |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1150 __ bind(&use_cache); | 1156 __ bind(&use_cache); |
| 1151 | 1157 |
| 1152 __ EnumLength(a1, v0); | 1158 __ EnumLength(a1, v0); |
| 1153 __ Branch(&no_descriptors, eq, a1, Operand(Smi::FromInt(0))); | 1159 __ Branch(&no_descriptors, eq, a1, Operand(Smi::FromInt(0))); |
| 1154 | 1160 |
| 1155 __ LoadInstanceDescriptors(v0, a2); | 1161 __ LoadInstanceDescriptors(v0, a2); |
| 1156 __ lw(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheOffset)); | 1162 __ lw(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheOffset)); |
| 1157 __ lw(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheBridgeCacheOffset)); | 1163 __ lw(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheBridgeCacheOffset)); |
| 1158 | 1164 |
| 1159 // Set up the four remaining stack slots. | 1165 // Set up the four remaining stack slots. |
| 1160 __ push(v0); // Map. | |
| 1161 __ li(a0, Operand(Smi::FromInt(0))); | 1166 __ li(a0, Operand(Smi::FromInt(0))); |
| 1162 // Push enumeration cache, enumeration cache length (as smi) and zero. | 1167 // Push map, enumeration cache, enumeration cache length (as smi) and zero. |
| 1163 __ Push(a2, a1, a0); | 1168 __ Push(v0, a2, a1, a0); |
| 1164 __ jmp(&loop); | 1169 __ jmp(&loop); |
| 1165 | 1170 |
| 1166 __ bind(&no_descriptors); | 1171 __ bind(&no_descriptors); |
| 1167 __ Drop(1); | 1172 __ Drop(1); |
| 1168 __ jmp(&exit); | 1173 __ jmp(&exit); |
| 1169 | 1174 |
| 1170 // We got a fixed array in register v0. Iterate through that. | 1175 // We got a fixed array in register v0. Iterate through that. |
| 1171 Label non_proxy; | 1176 Label non_proxy; |
| 1172 __ bind(&fixed_array); | 1177 __ bind(&fixed_array); |
| 1173 | 1178 |
| 1174 Handle<Cell> cell = isolate()->factory()->NewCell( | 1179 Handle<Object> feedback = Handle<Object>( |
| 1175 Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker), | 1180 Smi::FromInt(TypeFeedbackInfo::kForInFastCaseMarker), |
| 1176 isolate())); | 1181 isolate()); |
| 1177 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell); | 1182 StoreFeedbackVectorSlot(slot, feedback); |
| 1178 __ li(a1, cell); | 1183 __ li(a1, FeedbackVector()); |
| 1179 __ li(a2, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker))); | 1184 __ li(a2, Operand(Smi::FromInt(TypeFeedbackInfo::kForInSlowCaseMarker))); |
| 1180 __ sw(a2, FieldMemOperand(a1, Cell::kValueOffset)); | 1185 __ sw(a2, FieldMemOperand(a1, FixedArray::OffsetOfElementAt(slot))); |
| 1181 | 1186 |
| 1182 __ li(a1, Operand(Smi::FromInt(1))); // Smi indicates slow check | 1187 __ li(a1, Operand(Smi::FromInt(1))); // Smi indicates slow check |
| 1183 __ lw(a2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object | 1188 __ lw(a2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object |
| 1184 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); | 1189 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE); |
| 1185 __ GetObjectType(a2, a3, a3); | 1190 __ GetObjectType(a2, a3, a3); |
| 1186 __ Branch(&non_proxy, gt, a3, Operand(LAST_JS_PROXY_TYPE)); | 1191 __ Branch(&non_proxy, gt, a3, Operand(LAST_JS_PROXY_TYPE)); |
| 1187 __ li(a1, Operand(Smi::FromInt(0))); // Zero indicates proxy | 1192 __ li(a1, Operand(Smi::FromInt(0))); // Zero indicates proxy |
| 1188 __ bind(&non_proxy); | 1193 __ bind(&non_proxy); |
| 1189 __ Push(a1, v0); // Smi and array | 1194 __ Push(a1, v0); // Smi and array |
| 1190 __ lw(a1, FieldMemOperand(v0, FixedArray::kLengthOffset)); | 1195 __ lw(a1, FieldMemOperand(v0, FixedArray::kLengthOffset)); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1218 __ Branch(&update_each, eq, t0, Operand(a2)); | 1223 __ Branch(&update_each, eq, t0, Operand(a2)); |
| 1219 | 1224 |
| 1220 // For proxies, no filtering is done. | 1225 // For proxies, no filtering is done. |
| 1221 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet. | 1226 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet. |
| 1222 ASSERT_EQ(Smi::FromInt(0), 0); | 1227 ASSERT_EQ(Smi::FromInt(0), 0); |
| 1223 __ Branch(&update_each, eq, a2, Operand(zero_reg)); | 1228 __ Branch(&update_each, eq, a2, Operand(zero_reg)); |
| 1224 | 1229 |
| 1225 // Convert the entry to a string or (smi) 0 if it isn't a property | 1230 // Convert the entry to a string or (smi) 0 if it isn't a property |
| 1226 // any more. If the property has been removed while iterating, we | 1231 // any more. If the property has been removed while iterating, we |
| 1227 // just skip it. | 1232 // just skip it. |
| 1228 __ push(a1); // Enumerable. | 1233 __ Push(a1, a3); // Enumerable and current entry. |
| 1229 __ push(a3); // Current entry. | |
| 1230 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); | 1234 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); |
| 1231 __ mov(a3, result_register()); | 1235 __ mov(a3, result_register()); |
| 1232 __ Branch(loop_statement.continue_label(), eq, a3, Operand(zero_reg)); | 1236 __ Branch(loop_statement.continue_label(), eq, a3, Operand(zero_reg)); |
| 1233 | 1237 |
| 1234 // Update the 'each' property or variable from the possibly filtered | 1238 // Update the 'each' property or variable from the possibly filtered |
| 1235 // entry in register a3. | 1239 // entry in register a3. |
| 1236 __ bind(&update_each); | 1240 __ bind(&update_each); |
| 1237 __ mov(result_register(), a3); | 1241 __ mov(result_register(), a3); |
| 1238 // Perform the assignment as if via '='. | 1242 // Perform the assignment as if via '='. |
| 1239 { EffectContext context(this); | 1243 { EffectContext context(this); |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1479 | 1483 |
| 1480 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { | 1484 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { |
| 1481 // Record position before possible IC call. | 1485 // Record position before possible IC call. |
| 1482 SetSourcePosition(proxy->position()); | 1486 SetSourcePosition(proxy->position()); |
| 1483 Variable* var = proxy->var(); | 1487 Variable* var = proxy->var(); |
| 1484 | 1488 |
| 1485 // Three cases: global variables, lookup variables, and all other types of | 1489 // Three cases: global variables, lookup variables, and all other types of |
| 1486 // variables. | 1490 // variables. |
| 1487 switch (var->location()) { | 1491 switch (var->location()) { |
| 1488 case Variable::UNALLOCATED: { | 1492 case Variable::UNALLOCATED: { |
| 1489 Comment cmnt(masm_, "Global variable"); | 1493 Comment cmnt(masm_, "[ Global variable"); |
| 1490 // Use inline caching. Variable name is passed in a2 and the global | 1494 // Use inline caching. Variable name is passed in a2 and the global |
| 1491 // object (receiver) in a0. | 1495 // object (receiver) in a0. |
| 1492 __ lw(a0, GlobalObjectOperand()); | 1496 __ lw(a0, GlobalObjectOperand()); |
| 1493 __ li(a2, Operand(var->name())); | 1497 __ li(a2, Operand(var->name())); |
| 1494 CallLoadIC(CONTEXTUAL); | 1498 CallLoadIC(CONTEXTUAL); |
| 1495 context()->Plug(v0); | 1499 context()->Plug(v0); |
| 1496 break; | 1500 break; |
| 1497 } | 1501 } |
| 1498 | 1502 |
| 1499 case Variable::PARAMETER: | 1503 case Variable::PARAMETER: |
| 1500 case Variable::LOCAL: | 1504 case Variable::LOCAL: |
| 1501 case Variable::CONTEXT: { | 1505 case Variable::CONTEXT: { |
| 1502 Comment cmnt(masm_, var->IsContextSlot() | 1506 Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable" |
| 1503 ? "Context variable" | 1507 : "[ Stack variable"); |
| 1504 : "Stack variable"); | |
| 1505 if (var->binding_needs_init()) { | 1508 if (var->binding_needs_init()) { |
| 1506 // var->scope() may be NULL when the proxy is located in eval code and | 1509 // var->scope() may be NULL when the proxy is located in eval code and |
| 1507 // refers to a potential outside binding. Currently those bindings are | 1510 // refers to a potential outside binding. Currently those bindings are |
| 1508 // always looked up dynamically, i.e. in that case | 1511 // always looked up dynamically, i.e. in that case |
| 1509 // var->location() == LOOKUP. | 1512 // var->location() == LOOKUP. |
| 1510 // always holds. | 1513 // always holds. |
| 1511 ASSERT(var->scope() != NULL); | 1514 ASSERT(var->scope() != NULL); |
| 1512 | 1515 |
| 1513 // Check if the binding really needs an initialization check. The check | 1516 // Check if the binding really needs an initialization check. The check |
| 1514 // can be skipped in the following situation: we have a LET or CONST | 1517 // can be skipped in the following situation: we have a LET or CONST |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1559 } | 1562 } |
| 1560 context()->Plug(v0); | 1563 context()->Plug(v0); |
| 1561 break; | 1564 break; |
| 1562 } | 1565 } |
| 1563 } | 1566 } |
| 1564 context()->Plug(var); | 1567 context()->Plug(var); |
| 1565 break; | 1568 break; |
| 1566 } | 1569 } |
| 1567 | 1570 |
| 1568 case Variable::LOOKUP: { | 1571 case Variable::LOOKUP: { |
| 1572 Comment cmnt(masm_, "[ Lookup variable"); |
| 1569 Label done, slow; | 1573 Label done, slow; |
| 1570 // Generate code for loading from variables potentially shadowed | 1574 // Generate code for loading from variables potentially shadowed |
| 1571 // by eval-introduced variables. | 1575 // by eval-introduced variables. |
| 1572 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); | 1576 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done); |
| 1573 __ bind(&slow); | 1577 __ bind(&slow); |
| 1574 Comment cmnt(masm_, "Lookup variable"); | |
| 1575 __ li(a1, Operand(var->name())); | 1578 __ li(a1, Operand(var->name())); |
| 1576 __ Push(cp, a1); // Context and name. | 1579 __ Push(cp, a1); // Context and name. |
| 1577 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 1580 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
| 1578 __ bind(&done); | 1581 __ bind(&done); |
| 1579 context()->Plug(v0); | 1582 context()->Plug(v0); |
| 1580 } | 1583 } |
| 1581 } | 1584 } |
| 1582 } | 1585 } |
| 1583 | 1586 |
| 1584 | 1587 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1696 case ObjectLiteral::Property::MATERIALIZED_LITERAL: | 1699 case ObjectLiteral::Property::MATERIALIZED_LITERAL: |
| 1697 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); | 1700 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value())); |
| 1698 // Fall through. | 1701 // Fall through. |
| 1699 case ObjectLiteral::Property::COMPUTED: | 1702 case ObjectLiteral::Property::COMPUTED: |
| 1700 if (key->value()->IsInternalizedString()) { | 1703 if (key->value()->IsInternalizedString()) { |
| 1701 if (property->emit_store()) { | 1704 if (property->emit_store()) { |
| 1702 VisitForAccumulatorValue(value); | 1705 VisitForAccumulatorValue(value); |
| 1703 __ mov(a0, result_register()); | 1706 __ mov(a0, result_register()); |
| 1704 __ li(a2, Operand(key->value())); | 1707 __ li(a2, Operand(key->value())); |
| 1705 __ lw(a1, MemOperand(sp)); | 1708 __ lw(a1, MemOperand(sp)); |
| 1706 CallStoreIC(NOT_CONTEXTUAL, key->LiteralFeedbackId()); | 1709 CallStoreIC(key->LiteralFeedbackId()); |
| 1707 PrepareForBailoutForId(key->id(), NO_REGISTERS); | 1710 PrepareForBailoutForId(key->id(), NO_REGISTERS); |
| 1708 } else { | 1711 } else { |
| 1709 VisitForEffect(value); | 1712 VisitForEffect(value); |
| 1710 } | 1713 } |
| 1711 break; | 1714 break; |
| 1712 } | 1715 } |
| 1713 // Duplicate receiver on stack. | 1716 // Duplicate receiver on stack. |
| 1714 __ lw(a0, MemOperand(sp)); | 1717 __ lw(a0, MemOperand(sp)); |
| 1715 __ push(a0); | 1718 __ push(a0); |
| 1716 VisitForStackValue(key); | 1719 VisitForStackValue(key); |
| (...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2057 Label l_catch, l_try, l_suspend, l_continuation, l_resume; | 2060 Label l_catch, l_try, l_suspend, l_continuation, l_resume; |
| 2058 Label l_next, l_call, l_loop; | 2061 Label l_next, l_call, l_loop; |
| 2059 // Initial send value is undefined. | 2062 // Initial send value is undefined. |
| 2060 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); | 2063 __ LoadRoot(a0, Heap::kUndefinedValueRootIndex); |
| 2061 __ Branch(&l_next); | 2064 __ Branch(&l_next); |
| 2062 | 2065 |
| 2063 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; } | 2066 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; } |
| 2064 __ bind(&l_catch); | 2067 __ bind(&l_catch); |
| 2065 __ mov(a0, v0); | 2068 __ mov(a0, v0); |
| 2066 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); | 2069 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); |
| 2067 __ LoadRoot(a2, Heap::kthrow_stringRootIndex); // "throw" | 2070 __ LoadRoot(a2, Heap::kthrow_stringRootIndex); // "throw" |
| 2068 __ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter | 2071 __ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter |
| 2069 __ Push(a3, a0); // iter, exception | 2072 __ Push(a2, a3, a0); // "throw", iter, except |
| 2070 __ jmp(&l_call); | 2073 __ jmp(&l_call); |
| 2071 | 2074 |
| 2072 // try { received = %yield result } | 2075 // try { received = %yield result } |
| 2073 // Shuffle the received result above a try handler and yield it without | 2076 // Shuffle the received result above a try handler and yield it without |
| 2074 // re-boxing. | 2077 // re-boxing. |
| 2075 __ bind(&l_try); | 2078 __ bind(&l_try); |
| 2076 __ pop(a0); // result | 2079 __ pop(a0); // result |
| 2077 __ PushTryHandler(StackHandler::CATCH, expr->index()); | 2080 __ PushTryHandler(StackHandler::CATCH, expr->index()); |
| 2078 const int handler_size = StackHandlerConstants::kSize; | 2081 const int handler_size = StackHandlerConstants::kSize; |
| 2079 __ push(a0); // result | 2082 __ push(a0); // result |
| 2080 __ jmp(&l_suspend); | 2083 __ jmp(&l_suspend); |
| 2081 __ bind(&l_continuation); | 2084 __ bind(&l_continuation); |
| 2082 __ mov(a0, v0); | 2085 __ mov(a0, v0); |
| 2083 __ jmp(&l_resume); | 2086 __ jmp(&l_resume); |
| 2084 __ bind(&l_suspend); | 2087 __ bind(&l_suspend); |
| 2085 const int generator_object_depth = kPointerSize + handler_size; | 2088 const int generator_object_depth = kPointerSize + handler_size; |
| 2086 __ lw(a0, MemOperand(sp, generator_object_depth)); | 2089 __ lw(a0, MemOperand(sp, generator_object_depth)); |
| 2087 __ push(a0); // g | 2090 __ push(a0); // g |
| 2088 ASSERT(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos())); | 2091 ASSERT(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos())); |
| 2089 __ li(a1, Operand(Smi::FromInt(l_continuation.pos()))); | 2092 __ li(a1, Operand(Smi::FromInt(l_continuation.pos()))); |
| 2090 __ sw(a1, FieldMemOperand(a0, JSGeneratorObject::kContinuationOffset)); | 2093 __ sw(a1, FieldMemOperand(a0, JSGeneratorObject::kContinuationOffset)); |
| 2091 __ sw(cp, FieldMemOperand(a0, JSGeneratorObject::kContextOffset)); | 2094 __ sw(cp, FieldMemOperand(a0, JSGeneratorObject::kContextOffset)); |
| 2092 __ mov(a1, cp); | 2095 __ mov(a1, cp); |
| 2093 __ RecordWriteField(a0, JSGeneratorObject::kContextOffset, a1, a2, | 2096 __ RecordWriteField(a0, JSGeneratorObject::kContextOffset, a1, a2, |
| 2094 kRAHasBeenSaved, kDontSaveFPRegs); | 2097 kRAHasBeenSaved, kDontSaveFPRegs); |
| 2095 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); | 2098 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); |
| 2096 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2099 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2097 __ pop(v0); // result | 2100 __ pop(v0); // result |
| 2098 EmitReturnSequence(); | 2101 EmitReturnSequence(); |
| 2099 __ mov(a0, v0); | 2102 __ mov(a0, v0); |
| 2100 __ bind(&l_resume); // received in a0 | 2103 __ bind(&l_resume); // received in a0 |
| 2101 __ PopTryHandler(); | 2104 __ PopTryHandler(); |
| 2102 | 2105 |
| 2103 // receiver = iter; f = 'next'; arg = received; | 2106 // receiver = iter; f = 'next'; arg = received; |
| 2104 __ bind(&l_next); | 2107 __ bind(&l_next); |
| 2105 __ LoadRoot(a2, Heap::knext_stringRootIndex); // "next" | 2108 __ LoadRoot(a2, Heap::knext_stringRootIndex); // "next" |
| 2106 __ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter | 2109 __ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter |
| 2107 __ Push(a3, a0); // iter, received | 2110 __ Push(a2, a3, a0); // "next", iter, received |
| 2108 | 2111 |
| 2109 // result = receiver[f](arg); | 2112 // result = receiver[f](arg); |
| 2110 __ bind(&l_call); | 2113 __ bind(&l_call); |
| 2111 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); | 2114 __ lw(a1, MemOperand(sp, kPointerSize)); |
| 2112 CallIC(ic); | 2115 __ lw(a0, MemOperand(sp, 2 * kPointerSize)); |
| 2116 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2117 CallIC(ic, TypeFeedbackId::None()); |
| 2118 __ mov(a0, v0); |
| 2119 __ mov(a1, a0); |
| 2120 __ sw(a1, MemOperand(sp, 2 * kPointerSize)); |
| 2121 CallFunctionStub stub(1, CALL_AS_METHOD); |
| 2122 __ CallStub(&stub); |
| 2123 |
| 2113 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2124 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2125 __ Drop(1); // The function is still on the stack; drop it. |
| 2114 | 2126 |
| 2115 // if (!result.done) goto l_try; | 2127 // if (!result.done) goto l_try; |
| 2116 __ bind(&l_loop); | 2128 __ bind(&l_loop); |
| 2117 __ mov(a0, v0); | 2129 __ mov(a0, v0); |
| 2118 __ push(a0); // save result | 2130 __ push(a0); // save result |
| 2119 __ LoadRoot(a2, Heap::kdone_stringRootIndex); // "done" | 2131 __ LoadRoot(a2, Heap::kdone_stringRootIndex); // "done" |
| 2120 CallLoadIC(NOT_CONTEXTUAL); // result.done in v0 | 2132 CallLoadIC(NOT_CONTEXTUAL); // result.done in v0 |
| 2121 __ mov(a0, v0); | 2133 __ mov(a0, v0); |
| 2122 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); | 2134 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate()); |
| 2123 CallIC(bool_ic); | 2135 CallIC(bool_ic); |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2293 // Call load IC. It has arguments receiver and property name a0 and a2. | 2305 // Call load IC. It has arguments receiver and property name a0 and a2. |
| 2294 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); | 2306 CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId()); |
| 2295 } | 2307 } |
| 2296 | 2308 |
| 2297 | 2309 |
| 2298 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { | 2310 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
| 2299 SetSourcePosition(prop->position()); | 2311 SetSourcePosition(prop->position()); |
| 2300 __ mov(a0, result_register()); | 2312 __ mov(a0, result_register()); |
| 2301 // Call keyed load IC. It has arguments key and receiver in a0 and a1. | 2313 // Call keyed load IC. It has arguments key and receiver in a0 and a1. |
| 2302 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); | 2314 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize(); |
| 2303 CallIC(ic, NOT_CONTEXTUAL, prop->PropertyFeedbackId()); | 2315 CallIC(ic, prop->PropertyFeedbackId()); |
| 2304 } | 2316 } |
| 2305 | 2317 |
| 2306 | 2318 |
| 2307 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, | 2319 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr, |
| 2308 Token::Value op, | 2320 Token::Value op, |
| 2309 OverwriteMode mode, | 2321 OverwriteMode mode, |
| 2310 Expression* left_expr, | 2322 Expression* left_expr, |
| 2311 Expression* right_expr) { | 2323 Expression* right_expr) { |
| 2312 Label done, smi_case, stub_call; | 2324 Label done, smi_case, stub_call; |
| 2313 | 2325 |
| 2314 Register scratch1 = a2; | 2326 Register scratch1 = a2; |
| 2315 Register scratch2 = a3; | 2327 Register scratch2 = a3; |
| 2316 | 2328 |
| 2317 // Get the arguments. | 2329 // Get the arguments. |
| 2318 Register left = a1; | 2330 Register left = a1; |
| 2319 Register right = a0; | 2331 Register right = a0; |
| 2320 __ pop(left); | 2332 __ pop(left); |
| 2321 __ mov(a0, result_register()); | 2333 __ mov(a0, result_register()); |
| 2322 | 2334 |
| 2323 // Perform combined smi check on both operands. | 2335 // Perform combined smi check on both operands. |
| 2324 __ Or(scratch1, left, Operand(right)); | 2336 __ Or(scratch1, left, Operand(right)); |
| 2325 STATIC_ASSERT(kSmiTag == 0); | 2337 STATIC_ASSERT(kSmiTag == 0); |
| 2326 JumpPatchSite patch_site(masm_); | 2338 JumpPatchSite patch_site(masm_); |
| 2327 patch_site.EmitJumpIfSmi(scratch1, &smi_case); | 2339 patch_site.EmitJumpIfSmi(scratch1, &smi_case); |
| 2328 | 2340 |
| 2329 __ bind(&stub_call); | 2341 __ bind(&stub_call); |
| 2330 BinaryOpICStub stub(op, mode); | 2342 BinaryOpICStub stub(op, mode); |
| 2331 CallIC(stub.GetCode(isolate()), NOT_CONTEXTUAL, | 2343 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId()); |
| 2332 expr->BinaryOperationFeedbackId()); | |
| 2333 patch_site.EmitPatchInfo(); | 2344 patch_site.EmitPatchInfo(); |
| 2334 __ jmp(&done); | 2345 __ jmp(&done); |
| 2335 | 2346 |
| 2336 __ bind(&smi_case); | 2347 __ bind(&smi_case); |
| 2337 // Smi case. This code works the same way as the smi-smi case in the type | 2348 // Smi case. This code works the same way as the smi-smi case in the type |
| 2338 // recording binary operation stub, see | 2349 // recording binary operation stub, see |
| 2339 switch (op) { | 2350 switch (op) { |
| 2340 case Token::SAR: | 2351 case Token::SAR: |
| 2341 __ Branch(&stub_call); | |
| 2342 __ GetLeastBitsFromSmi(scratch1, right, 5); | 2352 __ GetLeastBitsFromSmi(scratch1, right, 5); |
| 2343 __ srav(right, left, scratch1); | 2353 __ srav(right, left, scratch1); |
| 2344 __ And(v0, right, Operand(~kSmiTagMask)); | 2354 __ And(v0, right, Operand(~kSmiTagMask)); |
| 2345 break; | 2355 break; |
| 2346 case Token::SHL: { | 2356 case Token::SHL: { |
| 2347 __ Branch(&stub_call); | |
| 2348 __ SmiUntag(scratch1, left); | 2357 __ SmiUntag(scratch1, left); |
| 2349 __ GetLeastBitsFromSmi(scratch2, right, 5); | 2358 __ GetLeastBitsFromSmi(scratch2, right, 5); |
| 2350 __ sllv(scratch1, scratch1, scratch2); | 2359 __ sllv(scratch1, scratch1, scratch2); |
| 2351 __ Addu(scratch2, scratch1, Operand(0x40000000)); | 2360 __ Addu(scratch2, scratch1, Operand(0x40000000)); |
| 2352 __ Branch(&stub_call, lt, scratch2, Operand(zero_reg)); | 2361 __ Branch(&stub_call, lt, scratch2, Operand(zero_reg)); |
| 2353 __ SmiTag(v0, scratch1); | 2362 __ SmiTag(v0, scratch1); |
| 2354 break; | 2363 break; |
| 2355 } | 2364 } |
| 2356 case Token::SHR: { | 2365 case Token::SHR: { |
| 2357 __ Branch(&stub_call); | |
| 2358 __ SmiUntag(scratch1, left); | 2366 __ SmiUntag(scratch1, left); |
| 2359 __ GetLeastBitsFromSmi(scratch2, right, 5); | 2367 __ GetLeastBitsFromSmi(scratch2, right, 5); |
| 2360 __ srlv(scratch1, scratch1, scratch2); | 2368 __ srlv(scratch1, scratch1, scratch2); |
| 2361 __ And(scratch2, scratch1, 0xc0000000); | 2369 __ And(scratch2, scratch1, 0xc0000000); |
| 2362 __ Branch(&stub_call, ne, scratch2, Operand(zero_reg)); | 2370 __ Branch(&stub_call, ne, scratch2, Operand(zero_reg)); |
| 2363 __ SmiTag(v0, scratch1); | 2371 __ SmiTag(v0, scratch1); |
| 2364 break; | 2372 break; |
| 2365 } | 2373 } |
| 2366 case Token::ADD: | 2374 case Token::ADD: |
| 2367 __ AdduAndCheckForOverflow(v0, left, right, scratch1); | 2375 __ AdduAndCheckForOverflow(v0, left, right, scratch1); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2404 } | 2412 } |
| 2405 | 2413 |
| 2406 | 2414 |
| 2407 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, | 2415 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, |
| 2408 Token::Value op, | 2416 Token::Value op, |
| 2409 OverwriteMode mode) { | 2417 OverwriteMode mode) { |
| 2410 __ mov(a0, result_register()); | 2418 __ mov(a0, result_register()); |
| 2411 __ pop(a1); | 2419 __ pop(a1); |
| 2412 BinaryOpICStub stub(op, mode); | 2420 BinaryOpICStub stub(op, mode); |
| 2413 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. | 2421 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code. |
| 2414 CallIC(stub.GetCode(isolate()), NOT_CONTEXTUAL, | 2422 CallIC(stub.GetCode(isolate()), expr->BinaryOperationFeedbackId()); |
| 2415 expr->BinaryOperationFeedbackId()); | |
| 2416 patch_site.EmitPatchInfo(); | 2423 patch_site.EmitPatchInfo(); |
| 2417 context()->Plug(v0); | 2424 context()->Plug(v0); |
| 2418 } | 2425 } |
| 2419 | 2426 |
| 2420 | 2427 |
| 2421 void FullCodeGenerator::EmitAssignment(Expression* expr) { | 2428 void FullCodeGenerator::EmitAssignment(Expression* expr) { |
| 2422 // Invalid left-hand sides are rewritten by the parser to have a 'throw | 2429 // Invalid left-hand sides are rewritten by the parser to have a 'throw |
| 2423 // ReferenceError' on the left-hand side. | 2430 // ReferenceError' on the left-hand side. |
| 2424 if (!expr->IsValidLeftHandSide()) { | 2431 if (!expr->IsValidLeftHandSide()) { |
| 2425 VisitForEffect(expr); | 2432 VisitForEffect(expr); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2443 EffectContext context(this); | 2450 EffectContext context(this); |
| 2444 EmitVariableAssignment(var, Token::ASSIGN); | 2451 EmitVariableAssignment(var, Token::ASSIGN); |
| 2445 break; | 2452 break; |
| 2446 } | 2453 } |
| 2447 case NAMED_PROPERTY: { | 2454 case NAMED_PROPERTY: { |
| 2448 __ push(result_register()); // Preserve value. | 2455 __ push(result_register()); // Preserve value. |
| 2449 VisitForAccumulatorValue(prop->obj()); | 2456 VisitForAccumulatorValue(prop->obj()); |
| 2450 __ mov(a1, result_register()); | 2457 __ mov(a1, result_register()); |
| 2451 __ pop(a0); // Restore value. | 2458 __ pop(a0); // Restore value. |
| 2452 __ li(a2, Operand(prop->key()->AsLiteral()->value())); | 2459 __ li(a2, Operand(prop->key()->AsLiteral()->value())); |
| 2453 CallStoreIC(NOT_CONTEXTUAL); | 2460 CallStoreIC(); |
| 2454 break; | 2461 break; |
| 2455 } | 2462 } |
| 2456 case KEYED_PROPERTY: { | 2463 case KEYED_PROPERTY: { |
| 2457 __ push(result_register()); // Preserve value. | 2464 __ push(result_register()); // Preserve value. |
| 2458 VisitForStackValue(prop->obj()); | 2465 VisitForStackValue(prop->obj()); |
| 2459 VisitForAccumulatorValue(prop->key()); | 2466 VisitForAccumulatorValue(prop->key()); |
| 2460 __ mov(a1, result_register()); | 2467 __ mov(a1, result_register()); |
| 2461 __ Pop(a0, a2); // a0 = restored value. | 2468 __ Pop(a0, a2); // a0 = restored value. |
| 2462 Handle<Code> ic = is_classic_mode() | 2469 Handle<Code> ic = is_classic_mode() |
| 2463 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2470 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2464 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2471 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2465 CallIC(ic); | 2472 CallIC(ic); |
| 2466 break; | 2473 break; |
| 2467 } | 2474 } |
| 2468 } | 2475 } |
| 2469 context()->Plug(v0); | 2476 context()->Plug(v0); |
| 2470 } | 2477 } |
| 2471 | 2478 |
| 2472 | 2479 |
| 2480 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot( |
| 2481 Variable* var, MemOperand location) { |
| 2482 __ sw(result_register(), location); |
| 2483 if (var->IsContextSlot()) { |
| 2484 // RecordWrite may destroy all its register arguments. |
| 2485 __ Move(a3, result_register()); |
| 2486 int offset = Context::SlotOffset(var->index()); |
| 2487 __ RecordWriteContextSlot( |
| 2488 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); |
| 2489 } |
| 2490 } |
| 2491 |
| 2492 |
| 2493 void FullCodeGenerator::EmitCallStoreContextSlot( |
| 2494 Handle<String> name, LanguageMode mode) { |
| 2495 __ li(a1, Operand(name)); |
| 2496 __ li(a0, Operand(Smi::FromInt(mode))); |
| 2497 __ Push(v0, cp, a1, a0); // Value, context, name, strict mode. |
| 2498 __ CallRuntime(Runtime::kStoreContextSlot, 4); |
| 2499 } |
| 2500 |
| 2501 |
| 2473 void FullCodeGenerator::EmitVariableAssignment(Variable* var, | 2502 void FullCodeGenerator::EmitVariableAssignment(Variable* var, |
| 2474 Token::Value op) { | 2503 Token::Value op) { |
| 2475 if (var->IsUnallocated()) { | 2504 if (var->IsUnallocated()) { |
| 2476 // Global var, const, or let. | 2505 // Global var, const, or let. |
| 2477 __ mov(a0, result_register()); | 2506 __ mov(a0, result_register()); |
| 2478 __ li(a2, Operand(var->name())); | 2507 __ li(a2, Operand(var->name())); |
| 2479 __ lw(a1, GlobalObjectOperand()); | 2508 __ lw(a1, GlobalObjectOperand()); |
| 2480 CallStoreIC(CONTEXTUAL); | 2509 CallStoreIC(); |
| 2510 |
| 2481 } else if (op == Token::INIT_CONST) { | 2511 } else if (op == Token::INIT_CONST) { |
| 2482 // Const initializers need a write barrier. | 2512 // Const initializers need a write barrier. |
| 2483 ASSERT(!var->IsParameter()); // No const parameters. | 2513 ASSERT(!var->IsParameter()); // No const parameters. |
| 2484 if (var->IsStackLocal()) { | 2514 if (var->IsLookupSlot()) { |
| 2515 __ li(a0, Operand(var->name())); |
| 2516 __ Push(v0, cp, a0); // Context and name. |
| 2517 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
| 2518 } else { |
| 2519 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
| 2485 Label skip; | 2520 Label skip; |
| 2486 __ lw(a1, StackOperand(var)); | 2521 MemOperand location = VarOperand(var, a1); |
| 2487 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 2522 __ lw(a2, location); |
| 2488 __ Branch(&skip, ne, a1, Operand(t0)); | 2523 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
| 2489 __ sw(result_register(), StackOperand(var)); | 2524 __ Branch(&skip, ne, a2, Operand(at)); |
| 2525 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2490 __ bind(&skip); | 2526 __ bind(&skip); |
| 2491 } else { | |
| 2492 ASSERT(var->IsContextSlot() || var->IsLookupSlot()); | |
| 2493 // Like var declarations, const declarations are hoisted to function | |
| 2494 // scope. However, unlike var initializers, const initializers are | |
| 2495 // able to drill a hole to that function context, even from inside a | |
| 2496 // 'with' context. We thus bypass the normal static scope lookup for | |
| 2497 // var->IsContextSlot(). | |
| 2498 __ push(v0); | |
| 2499 __ li(a0, Operand(var->name())); | |
| 2500 __ Push(cp, a0); // Context and name. | |
| 2501 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
| 2502 } | 2527 } |
| 2503 | 2528 |
| 2504 } else if (var->mode() == LET && op != Token::INIT_LET) { | 2529 } else if (var->mode() == LET && op != Token::INIT_LET) { |
| 2505 // Non-initializing assignment to let variable needs a write barrier. | 2530 // Non-initializing assignment to let variable needs a write barrier. |
| 2506 if (var->IsLookupSlot()) { | 2531 if (var->IsLookupSlot()) { |
| 2507 __ push(v0); // Value. | 2532 EmitCallStoreContextSlot(var->name(), language_mode()); |
| 2508 __ li(a1, Operand(var->name())); | |
| 2509 __ li(a0, Operand(Smi::FromInt(language_mode()))); | |
| 2510 __ Push(cp, a1, a0); // Context, name, strict mode. | |
| 2511 __ CallRuntime(Runtime::kStoreContextSlot, 4); | |
| 2512 } else { | 2533 } else { |
| 2513 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); | 2534 ASSERT(var->IsStackAllocated() || var->IsContextSlot()); |
| 2514 Label assign; | 2535 Label assign; |
| 2515 MemOperand location = VarOperand(var, a1); | 2536 MemOperand location = VarOperand(var, a1); |
| 2516 __ lw(a3, location); | 2537 __ lw(a3, location); |
| 2517 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 2538 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
| 2518 __ Branch(&assign, ne, a3, Operand(t0)); | 2539 __ Branch(&assign, ne, a3, Operand(t0)); |
| 2519 __ li(a3, Operand(var->name())); | 2540 __ li(a3, Operand(var->name())); |
| 2520 __ push(a3); | 2541 __ push(a3); |
| 2521 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 2542 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
| 2522 // Perform the assignment. | 2543 // Perform the assignment. |
| 2523 __ bind(&assign); | 2544 __ bind(&assign); |
| 2524 __ sw(result_register(), location); | 2545 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2525 if (var->IsContextSlot()) { | |
| 2526 // RecordWrite may destroy all its register arguments. | |
| 2527 __ mov(a3, result_register()); | |
| 2528 int offset = Context::SlotOffset(var->index()); | |
| 2529 __ RecordWriteContextSlot( | |
| 2530 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); | |
| 2531 } | |
| 2532 } | 2546 } |
| 2533 | 2547 |
| 2534 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { | 2548 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) { |
| 2535 // Assignment to var or initializing assignment to let/const | 2549 // Assignment to var or initializing assignment to let/const |
| 2536 // in harmony mode. | 2550 // in harmony mode. |
| 2537 if (var->IsStackAllocated() || var->IsContextSlot()) { | 2551 if (var->IsLookupSlot()) { |
| 2552 EmitCallStoreContextSlot(var->name(), language_mode()); |
| 2553 } else { |
| 2554 ASSERT((var->IsStackAllocated() || var->IsContextSlot())); |
| 2538 MemOperand location = VarOperand(var, a1); | 2555 MemOperand location = VarOperand(var, a1); |
| 2539 if (generate_debug_code_ && op == Token::INIT_LET) { | 2556 if (generate_debug_code_ && op == Token::INIT_LET) { |
| 2540 // Check for an uninitialized let binding. | 2557 // Check for an uninitialized let binding. |
| 2541 __ lw(a2, location); | 2558 __ lw(a2, location); |
| 2542 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); | 2559 __ LoadRoot(t0, Heap::kTheHoleValueRootIndex); |
| 2543 __ Check(eq, kLetBindingReInitialization, a2, Operand(t0)); | 2560 __ Check(eq, kLetBindingReInitialization, a2, Operand(t0)); |
| 2544 } | 2561 } |
| 2545 // Perform the assignment. | 2562 EmitStoreToStackLocalOrContextSlot(var, location); |
| 2546 __ sw(v0, location); | |
| 2547 if (var->IsContextSlot()) { | |
| 2548 __ mov(a3, v0); | |
| 2549 int offset = Context::SlotOffset(var->index()); | |
| 2550 __ RecordWriteContextSlot( | |
| 2551 a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs); | |
| 2552 } | |
| 2553 } else { | |
| 2554 ASSERT(var->IsLookupSlot()); | |
| 2555 __ push(v0); // Value. | |
| 2556 __ li(a1, Operand(var->name())); | |
| 2557 __ li(a0, Operand(Smi::FromInt(language_mode()))); | |
| 2558 __ Push(cp, a1, a0); // Context, name, strict mode. | |
| 2559 __ CallRuntime(Runtime::kStoreContextSlot, 4); | |
| 2560 } | 2563 } |
| 2561 } | 2564 } |
| 2562 // Non-initializing assignments to consts are ignored. | 2565 // Non-initializing assignments to consts are ignored. |
| 2563 } | 2566 } |
| 2564 | 2567 |
| 2565 | 2568 |
| 2566 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { | 2569 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { |
| 2567 // Assignment to a property, using a named store IC. | 2570 // Assignment to a property, using a named store IC. |
| 2568 Property* prop = expr->target()->AsProperty(); | 2571 Property* prop = expr->target()->AsProperty(); |
| 2569 ASSERT(prop != NULL); | 2572 ASSERT(prop != NULL); |
| 2570 ASSERT(prop->key()->AsLiteral() != NULL); | 2573 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2571 | 2574 |
| 2572 // Record source code position before IC call. | 2575 // Record source code position before IC call. |
| 2573 SetSourcePosition(expr->position()); | 2576 SetSourcePosition(expr->position()); |
| 2574 __ mov(a0, result_register()); // Load the value. | 2577 __ mov(a0, result_register()); // Load the value. |
| 2575 __ li(a2, Operand(prop->key()->AsLiteral()->value())); | 2578 __ li(a2, Operand(prop->key()->AsLiteral()->value())); |
| 2576 __ pop(a1); | 2579 __ pop(a1); |
| 2577 | 2580 |
| 2578 CallStoreIC(NOT_CONTEXTUAL, expr->AssignmentFeedbackId()); | 2581 CallStoreIC(expr->AssignmentFeedbackId()); |
| 2579 | 2582 |
| 2580 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2583 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2581 context()->Plug(v0); | 2584 context()->Plug(v0); |
| 2582 } | 2585 } |
| 2583 | 2586 |
| 2584 | 2587 |
| 2585 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { | 2588 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) { |
| 2586 // Assignment to a property, using a keyed store IC. | 2589 // Assignment to a property, using a keyed store IC. |
| 2587 | 2590 |
| 2588 // Record source code position before IC call. | 2591 // Record source code position before IC call. |
| 2589 SetSourcePosition(expr->position()); | 2592 SetSourcePosition(expr->position()); |
| 2590 // Call keyed store IC. | 2593 // Call keyed store IC. |
| 2591 // The arguments are: | 2594 // The arguments are: |
| 2592 // - a0 is the value, | 2595 // - a0 is the value, |
| 2593 // - a1 is the key, | 2596 // - a1 is the key, |
| 2594 // - a2 is the receiver. | 2597 // - a2 is the receiver. |
| 2595 __ mov(a0, result_register()); | 2598 __ mov(a0, result_register()); |
| 2596 __ Pop(a2, a1); // a1 = key. | 2599 __ Pop(a2, a1); // a1 = key. |
| 2597 | 2600 |
| 2598 Handle<Code> ic = is_classic_mode() | 2601 Handle<Code> ic = is_classic_mode() |
| 2599 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 2602 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 2600 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 2603 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 2601 CallIC(ic, NOT_CONTEXTUAL, expr->AssignmentFeedbackId()); | 2604 CallIC(ic, expr->AssignmentFeedbackId()); |
| 2602 | 2605 |
| 2603 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 2606 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 2604 context()->Plug(v0); | 2607 context()->Plug(v0); |
| 2605 } | 2608 } |
| 2606 | 2609 |
| 2607 | 2610 |
| 2608 void FullCodeGenerator::VisitProperty(Property* expr) { | 2611 void FullCodeGenerator::VisitProperty(Property* expr) { |
| 2609 Comment cmnt(masm_, "[ Property"); | 2612 Comment cmnt(masm_, "[ Property"); |
| 2610 Expression* key = expr->key(); | 2613 Expression* key = expr->key(); |
| 2611 | 2614 |
| 2612 if (key->IsPropertyName()) { | 2615 if (key->IsPropertyName()) { |
| 2613 VisitForAccumulatorValue(expr->obj()); | 2616 VisitForAccumulatorValue(expr->obj()); |
| 2614 EmitNamedPropertyLoad(expr); | 2617 EmitNamedPropertyLoad(expr); |
| 2615 PrepareForBailoutForId(expr->LoadId(), TOS_REG); | 2618 PrepareForBailoutForId(expr->LoadId(), TOS_REG); |
| 2616 context()->Plug(v0); | 2619 context()->Plug(v0); |
| 2617 } else { | 2620 } else { |
| 2618 VisitForStackValue(expr->obj()); | 2621 VisitForStackValue(expr->obj()); |
| 2619 VisitForAccumulatorValue(expr->key()); | 2622 VisitForAccumulatorValue(expr->key()); |
| 2620 __ pop(a1); | 2623 __ pop(a1); |
| 2621 EmitKeyedPropertyLoad(expr); | 2624 EmitKeyedPropertyLoad(expr); |
| 2622 context()->Plug(v0); | 2625 context()->Plug(v0); |
| 2623 } | 2626 } |
| 2624 } | 2627 } |
| 2625 | 2628 |
| 2626 | 2629 |
| 2627 void FullCodeGenerator::CallIC(Handle<Code> code, | 2630 void FullCodeGenerator::CallIC(Handle<Code> code, |
| 2628 ContextualMode mode, | |
| 2629 TypeFeedbackId id) { | 2631 TypeFeedbackId id) { |
| 2630 ic_total_count_++; | 2632 ic_total_count_++; |
| 2631 ASSERT(mode != CONTEXTUAL || id.IsNone()); | |
| 2632 __ Call(code, RelocInfo::CODE_TARGET, id); | 2633 __ Call(code, RelocInfo::CODE_TARGET, id); |
| 2633 } | 2634 } |
| 2634 | 2635 |
| 2635 | 2636 |
| 2636 void FullCodeGenerator::EmitCallWithIC(Call* expr, | 2637 // Code common for calls using the IC. |
| 2637 Handle<Object> name, | 2638 void FullCodeGenerator::EmitCallWithIC(Call* expr) { |
| 2638 ContextualMode mode) { | 2639 Expression* callee = expr->expression(); |
| 2639 // Code common for calls using the IC. | |
| 2640 ZoneList<Expression*>* args = expr->arguments(); | 2640 ZoneList<Expression*>* args = expr->arguments(); |
| 2641 int arg_count = args->length(); | 2641 int arg_count = args->length(); |
| 2642 { PreservePositionScope scope(masm()->positions_recorder()); | 2642 |
| 2643 for (int i = 0; i < arg_count; i++) { | 2643 CallFunctionFlags flags; |
| 2644 VisitForStackValue(args->at(i)); | 2644 // Get the target function. |
| 2645 if (callee->IsVariableProxy()) { |
| 2646 { StackValueContext context(this); |
| 2647 EmitVariableLoad(callee->AsVariableProxy()); |
| 2648 PrepareForBailout(callee, NO_REGISTERS); |
| 2645 } | 2649 } |
| 2646 __ li(a2, Operand(name)); | 2650 // Push undefined as receiver. This is patched in the method prologue if it |
| 2651 // is a classic mode method. |
| 2652 __ Push(isolate()->factory()->undefined_value()); |
| 2653 flags = NO_CALL_FUNCTION_FLAGS; |
| 2654 } else { |
| 2655 // Load the function from the receiver. |
| 2656 ASSERT(callee->IsProperty()); |
| 2657 __ lw(v0, MemOperand(sp, 0)); |
| 2658 EmitNamedPropertyLoad(callee->AsProperty()); |
| 2659 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); |
| 2660 // Push the target function under the receiver. |
| 2661 __ lw(at, MemOperand(sp, 0)); |
| 2662 __ push(at); |
| 2663 __ sw(v0, MemOperand(sp, kPointerSize)); |
| 2664 flags = CALL_AS_METHOD; |
| 2647 } | 2665 } |
| 2648 // Record source position for debugger. | |
| 2649 SetSourcePosition(expr->position()); | |
| 2650 // Call the IC initialization code. | |
| 2651 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count); | |
| 2652 TypeFeedbackId ast_id = mode == CONTEXTUAL | |
| 2653 ? TypeFeedbackId::None() | |
| 2654 : expr->CallFeedbackId(); | |
| 2655 CallIC(ic, mode, ast_id); | |
| 2656 RecordJSReturnSite(expr); | |
| 2657 // Restore context register. | |
| 2658 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | |
| 2659 context()->Plug(v0); | |
| 2660 } | |
| 2661 | 2666 |
| 2662 | 2667 // Load the arguments. |
| 2663 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, | |
| 2664 Expression* key) { | |
| 2665 // Load the key. | |
| 2666 VisitForAccumulatorValue(key); | |
| 2667 | |
| 2668 // Swap the name of the function and the receiver on the stack to follow | |
| 2669 // the calling convention for call ICs. | |
| 2670 __ pop(a1); | |
| 2671 __ push(v0); | |
| 2672 __ push(a1); | |
| 2673 | |
| 2674 // Code common for calls using the IC. | |
| 2675 ZoneList<Expression*>* args = expr->arguments(); | |
| 2676 int arg_count = args->length(); | |
| 2677 { PreservePositionScope scope(masm()->positions_recorder()); | 2668 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2678 for (int i = 0; i < arg_count; i++) { | 2669 for (int i = 0; i < arg_count; i++) { |
| 2679 VisitForStackValue(args->at(i)); | 2670 VisitForStackValue(args->at(i)); |
| 2680 } | 2671 } |
| 2681 } | 2672 } |
| 2682 // Record source position for debugger. | 2673 // Record source position for debugger. |
| 2683 SetSourcePosition(expr->position()); | 2674 SetSourcePosition(expr->position()); |
| 2684 // Call the IC initialization code. | 2675 CallFunctionStub stub(arg_count, flags); |
| 2685 Handle<Code> ic = | 2676 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 2686 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); | 2677 __ CallStub(&stub); |
| 2687 __ lw(a2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key. | 2678 |
| 2688 CallIC(ic, NOT_CONTEXTUAL, expr->CallFeedbackId()); | 2679 RecordJSReturnSite(expr); |
| 2680 |
| 2681 // Restore context register. |
| 2682 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2683 |
| 2684 context()->DropAndPlug(1, v0); |
| 2685 } |
| 2686 |
| 2687 |
| 2688 // Code common for calls using the IC. |
| 2689 void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr, |
| 2690 Expression* key) { |
| 2691 // Load the key. |
| 2692 VisitForAccumulatorValue(key); |
| 2693 |
| 2694 Expression* callee = expr->expression(); |
| 2695 ZoneList<Expression*>* args = expr->arguments(); |
| 2696 int arg_count = args->length(); |
| 2697 |
| 2698 // Load the function from the receiver. |
| 2699 ASSERT(callee->IsProperty()); |
| 2700 __ lw(a1, MemOperand(sp, 0)); |
| 2701 EmitKeyedPropertyLoad(callee->AsProperty()); |
| 2702 PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG); |
| 2703 |
| 2704 // Push the target function under the receiver. |
| 2705 __ lw(at, MemOperand(sp, 0)); |
| 2706 __ push(at); |
| 2707 __ sw(v0, MemOperand(sp, kPointerSize)); |
| 2708 |
| 2709 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2710 for (int i = 0; i < arg_count; i++) { |
| 2711 VisitForStackValue(args->at(i)); |
| 2712 } |
| 2713 } |
| 2714 |
| 2715 // Record source position for debugger. |
| 2716 SetSourcePosition(expr->position()); |
| 2717 CallFunctionStub stub(arg_count, CALL_AS_METHOD); |
| 2718 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 2719 __ CallStub(&stub); |
| 2720 |
| 2689 RecordJSReturnSite(expr); | 2721 RecordJSReturnSite(expr); |
| 2690 // Restore context register. | 2722 // Restore context register. |
| 2691 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2723 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2692 context()->DropAndPlug(1, v0); // Drop the key still on the stack. | 2724 |
| 2725 context()->DropAndPlug(1, v0); |
| 2693 } | 2726 } |
| 2694 | 2727 |
| 2695 | 2728 |
| 2696 void FullCodeGenerator::EmitCallWithStub(Call* expr) { | 2729 void FullCodeGenerator::EmitCallWithStub(Call* expr) { |
| 2697 // Code common for calls using the call stub. | 2730 // Code common for calls using the call stub. |
| 2698 ZoneList<Expression*>* args = expr->arguments(); | 2731 ZoneList<Expression*>* args = expr->arguments(); |
| 2699 int arg_count = args->length(); | 2732 int arg_count = args->length(); |
| 2700 { PreservePositionScope scope(masm()->positions_recorder()); | 2733 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2701 for (int i = 0; i < arg_count; i++) { | 2734 for (int i = 0; i < arg_count; i++) { |
| 2702 VisitForStackValue(args->at(i)); | 2735 VisitForStackValue(args->at(i)); |
| 2703 } | 2736 } |
| 2704 } | 2737 } |
| 2705 // Record source position for debugger. | 2738 // Record source position for debugger. |
| 2706 SetSourcePosition(expr->position()); | 2739 SetSourcePosition(expr->position()); |
| 2707 | 2740 |
| 2708 Handle<Object> uninitialized = | 2741 Handle<Object> uninitialized = |
| 2709 TypeFeedbackCells::UninitializedSentinel(isolate()); | 2742 TypeFeedbackInfo::UninitializedSentinel(isolate()); |
| 2710 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); | 2743 StoreFeedbackVectorSlot(expr->CallFeedbackSlot(), uninitialized); |
| 2711 RecordTypeFeedbackCell(expr->CallFeedbackId(), cell); | 2744 __ li(a2, FeedbackVector()); |
| 2712 __ li(a2, Operand(cell)); | 2745 __ li(a3, Operand(Smi::FromInt(expr->CallFeedbackSlot()))); |
| 2713 | 2746 |
| 2714 // Record call targets in unoptimized code. | 2747 // Record call targets in unoptimized code. |
| 2715 CallFunctionStub stub(arg_count, RECORD_CALL_TARGET); | 2748 CallFunctionStub stub(arg_count, RECORD_CALL_TARGET); |
| 2716 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize)); | 2749 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 2717 __ CallStub(&stub, expr->CallFeedbackId()); | 2750 __ CallStub(&stub); |
| 2718 RecordJSReturnSite(expr); | 2751 RecordJSReturnSite(expr); |
| 2719 // Restore context register. | 2752 // Restore context register. |
| 2720 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2753 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2721 context()->DropAndPlug(1, v0); | 2754 context()->DropAndPlug(1, v0); |
| 2722 } | 2755 } |
| 2723 | 2756 |
| 2724 | 2757 |
| 2725 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { | 2758 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { |
| 2726 // t2: copy of the first argument or undefined if it doesn't exist. | 2759 // t2: copy of the first argument or undefined if it doesn't exist. |
| 2727 if (arg_count > 0) { | 2760 if (arg_count > 0) { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2789 // Record source position for debugger. | 2822 // Record source position for debugger. |
| 2790 SetSourcePosition(expr->position()); | 2823 SetSourcePosition(expr->position()); |
| 2791 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); | 2824 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); |
| 2792 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize)); | 2825 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 2793 __ CallStub(&stub); | 2826 __ CallStub(&stub); |
| 2794 RecordJSReturnSite(expr); | 2827 RecordJSReturnSite(expr); |
| 2795 // Restore context register. | 2828 // Restore context register. |
| 2796 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 2829 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 2797 context()->DropAndPlug(1, v0); | 2830 context()->DropAndPlug(1, v0); |
| 2798 } else if (call_type == Call::GLOBAL_CALL) { | 2831 } else if (call_type == Call::GLOBAL_CALL) { |
| 2799 // Push global object as receiver for the call IC. | 2832 EmitCallWithIC(expr); |
| 2800 __ lw(a0, GlobalObjectOperand()); | |
| 2801 __ push(a0); | |
| 2802 VariableProxy* proxy = callee->AsVariableProxy(); | |
| 2803 EmitCallWithIC(expr, proxy->name(), CONTEXTUAL); | |
| 2804 } else if (call_type == Call::LOOKUP_SLOT_CALL) { | 2833 } else if (call_type == Call::LOOKUP_SLOT_CALL) { |
| 2805 // Call to a lookup slot (dynamically introduced variable). | 2834 // Call to a lookup slot (dynamically introduced variable). |
| 2806 VariableProxy* proxy = callee->AsVariableProxy(); | 2835 VariableProxy* proxy = callee->AsVariableProxy(); |
| 2807 Label slow, done; | 2836 Label slow, done; |
| 2808 | 2837 |
| 2809 { PreservePositionScope scope(masm()->positions_recorder()); | 2838 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2810 // Generate code for loading from variables potentially shadowed | 2839 // Generate code for loading from variables potentially shadowed |
| 2811 // by eval-introduced variables. | 2840 // by eval-introduced variables. |
| 2812 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); | 2841 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done); |
| 2813 } | 2842 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 2839 | 2868 |
| 2840 // The receiver is either the global receiver or an object found | 2869 // The receiver is either the global receiver or an object found |
| 2841 // by LoadContextSlot. | 2870 // by LoadContextSlot. |
| 2842 EmitCallWithStub(expr); | 2871 EmitCallWithStub(expr); |
| 2843 } else if (call_type == Call::PROPERTY_CALL) { | 2872 } else if (call_type == Call::PROPERTY_CALL) { |
| 2844 Property* property = callee->AsProperty(); | 2873 Property* property = callee->AsProperty(); |
| 2845 { PreservePositionScope scope(masm()->positions_recorder()); | 2874 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2846 VisitForStackValue(property->obj()); | 2875 VisitForStackValue(property->obj()); |
| 2847 } | 2876 } |
| 2848 if (property->key()->IsPropertyName()) { | 2877 if (property->key()->IsPropertyName()) { |
| 2849 EmitCallWithIC(expr, | 2878 EmitCallWithIC(expr); |
| 2850 property->key()->AsLiteral()->value(), | |
| 2851 NOT_CONTEXTUAL); | |
| 2852 } else { | 2879 } else { |
| 2853 EmitKeyedCallWithIC(expr, property->key()); | 2880 EmitKeyedCallWithIC(expr, property->key()); |
| 2854 } | 2881 } |
| 2855 } else { | 2882 } else { |
| 2856 ASSERT(call_type == Call::OTHER_CALL); | 2883 ASSERT(call_type == Call::OTHER_CALL); |
| 2857 // Call to an arbitrary expression not handled specially above. | 2884 // Call to an arbitrary expression not handled specially above. |
| 2858 { PreservePositionScope scope(masm()->positions_recorder()); | 2885 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2859 VisitForStackValue(callee); | 2886 VisitForStackValue(callee); |
| 2860 } | 2887 } |
| 2861 __ LoadRoot(a1, Heap::kUndefinedValueRootIndex); | 2888 __ LoadRoot(a1, Heap::kUndefinedValueRootIndex); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2892 // Call the construct call builtin that handles allocation and | 2919 // Call the construct call builtin that handles allocation and |
| 2893 // constructor invocation. | 2920 // constructor invocation. |
| 2894 SetSourcePosition(expr->position()); | 2921 SetSourcePosition(expr->position()); |
| 2895 | 2922 |
| 2896 // Load function and argument count into a1 and a0. | 2923 // Load function and argument count into a1 and a0. |
| 2897 __ li(a0, Operand(arg_count)); | 2924 __ li(a0, Operand(arg_count)); |
| 2898 __ lw(a1, MemOperand(sp, arg_count * kPointerSize)); | 2925 __ lw(a1, MemOperand(sp, arg_count * kPointerSize)); |
| 2899 | 2926 |
| 2900 // Record call targets in unoptimized code. | 2927 // Record call targets in unoptimized code. |
| 2901 Handle<Object> uninitialized = | 2928 Handle<Object> uninitialized = |
| 2902 TypeFeedbackCells::UninitializedSentinel(isolate()); | 2929 TypeFeedbackInfo::UninitializedSentinel(isolate()); |
| 2903 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized); | 2930 StoreFeedbackVectorSlot(expr->CallNewFeedbackSlot(), uninitialized); |
| 2904 RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell); | 2931 __ li(a2, FeedbackVector()); |
| 2905 __ li(a2, Operand(cell)); | 2932 __ li(a3, Operand(Smi::FromInt(expr->CallNewFeedbackSlot()))); |
| 2906 | 2933 |
| 2907 CallConstructStub stub(RECORD_CALL_TARGET); | 2934 CallConstructStub stub(RECORD_CALL_TARGET); |
| 2908 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); | 2935 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL); |
| 2909 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); | 2936 PrepareForBailoutForId(expr->ReturnId(), TOS_REG); |
| 2910 context()->Plug(v0); | 2937 context()->Plug(v0); |
| 2911 } | 2938 } |
| 2912 | 2939 |
| 2913 | 2940 |
| 2914 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { | 2941 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) { |
| 2915 ZoneList<Expression*>* args = expr->arguments(); | 2942 ZoneList<Expression*>* args = expr->arguments(); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3016 Label materialize_true, materialize_false; | 3043 Label materialize_true, materialize_false; |
| 3017 Label* if_true = NULL; | 3044 Label* if_true = NULL; |
| 3018 Label* if_false = NULL; | 3045 Label* if_false = NULL; |
| 3019 Label* fall_through = NULL; | 3046 Label* fall_through = NULL; |
| 3020 context()->PrepareTest(&materialize_true, &materialize_false, | 3047 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3021 &if_true, &if_false, &fall_through); | 3048 &if_true, &if_false, &fall_through); |
| 3022 | 3049 |
| 3023 __ JumpIfSmi(v0, if_false); | 3050 __ JumpIfSmi(v0, if_false); |
| 3024 __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset)); | 3051 __ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset)); |
| 3025 __ lbu(a1, FieldMemOperand(a1, Map::kBitFieldOffset)); | 3052 __ lbu(a1, FieldMemOperand(a1, Map::kBitFieldOffset)); |
| 3053 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 3026 __ And(at, a1, Operand(1 << Map::kIsUndetectable)); | 3054 __ And(at, a1, Operand(1 << Map::kIsUndetectable)); |
| 3027 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | |
| 3028 Split(ne, at, Operand(zero_reg), if_true, if_false, fall_through); | 3055 Split(ne, at, Operand(zero_reg), if_true, if_false, fall_through); |
| 3029 | 3056 |
| 3030 context()->Plug(if_true, if_false); | 3057 context()->Plug(if_true, if_false); |
| 3031 } | 3058 } |
| 3032 | 3059 |
| 3033 | 3060 |
| 3034 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( | 3061 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf( |
| 3035 CallRuntime* expr) { | 3062 CallRuntime* expr) { |
| 3036 ZoneList<Expression*>* args = expr->arguments(); | 3063 ZoneList<Expression*>* args = expr->arguments(); |
| 3037 ASSERT(args->length() == 1); | 3064 ASSERT(args->length() == 1); |
| (...skipping 453 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3491 Register index = a1; | 3518 Register index = a1; |
| 3492 Register value = a2; | 3519 Register value = a2; |
| 3493 | 3520 |
| 3494 VisitForStackValue(args->at(1)); // index | 3521 VisitForStackValue(args->at(1)); // index |
| 3495 VisitForStackValue(args->at(2)); // value | 3522 VisitForStackValue(args->at(2)); // value |
| 3496 VisitForAccumulatorValue(args->at(0)); // string | 3523 VisitForAccumulatorValue(args->at(0)); // string |
| 3497 __ Pop(index, value); | 3524 __ Pop(index, value); |
| 3498 | 3525 |
| 3499 if (FLAG_debug_code) { | 3526 if (FLAG_debug_code) { |
| 3500 __ SmiTst(value, at); | 3527 __ SmiTst(value, at); |
| 3501 __ ThrowIf(ne, kNonSmiValue, at, Operand(zero_reg)); | 3528 __ Check(eq, kNonSmiValue, at, Operand(zero_reg)); |
| 3502 __ SmiTst(index, at); | 3529 __ SmiTst(index, at); |
| 3503 __ ThrowIf(ne, kNonSmiIndex, at, Operand(zero_reg)); | 3530 __ Check(eq, kNonSmiIndex, at, Operand(zero_reg)); |
| 3504 __ SmiUntag(index, index); | 3531 __ SmiUntag(index, index); |
| 3505 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; | 3532 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag; |
| 3506 Register scratch = t5; | 3533 Register scratch = t5; |
| 3507 __ EmitSeqStringSetCharCheck( | 3534 __ EmitSeqStringSetCharCheck( |
| 3508 string, index, value, scratch, one_byte_seq_type); | 3535 string, index, value, scratch, one_byte_seq_type); |
| 3509 __ SmiTag(index, index); | 3536 __ SmiTag(index, index); |
| 3510 } | 3537 } |
| 3511 | 3538 |
| 3512 __ SmiUntag(value, value); | 3539 __ SmiUntag(value, value); |
| 3513 __ Addu(at, | 3540 __ Addu(at, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3528 Register index = a1; | 3555 Register index = a1; |
| 3529 Register value = a2; | 3556 Register value = a2; |
| 3530 | 3557 |
| 3531 VisitForStackValue(args->at(1)); // index | 3558 VisitForStackValue(args->at(1)); // index |
| 3532 VisitForStackValue(args->at(2)); // value | 3559 VisitForStackValue(args->at(2)); // value |
| 3533 VisitForAccumulatorValue(args->at(0)); // string | 3560 VisitForAccumulatorValue(args->at(0)); // string |
| 3534 __ Pop(index, value); | 3561 __ Pop(index, value); |
| 3535 | 3562 |
| 3536 if (FLAG_debug_code) { | 3563 if (FLAG_debug_code) { |
| 3537 __ SmiTst(value, at); | 3564 __ SmiTst(value, at); |
| 3538 __ ThrowIf(ne, kNonSmiValue, at, Operand(zero_reg)); | 3565 __ Check(eq, kNonSmiValue, at, Operand(zero_reg)); |
| 3539 __ SmiTst(index, at); | 3566 __ SmiTst(index, at); |
| 3540 __ ThrowIf(ne, kNonSmiIndex, at, Operand(zero_reg)); | 3567 __ Check(eq, kNonSmiIndex, at, Operand(zero_reg)); |
| 3541 __ SmiUntag(index, index); | 3568 __ SmiUntag(index, index); |
| 3542 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; | 3569 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag; |
| 3543 Register scratch = t5; | 3570 Register scratch = t5; |
| 3544 __ EmitSeqStringSetCharCheck( | 3571 __ EmitSeqStringSetCharCheck( |
| 3545 string, index, value, scratch, two_byte_seq_type); | 3572 string, index, value, scratch, two_byte_seq_type); |
| 3546 __ SmiTag(index, index); | 3573 __ SmiTag(index, index); |
| 3547 } | 3574 } |
| 3548 | 3575 |
| 3549 __ SmiUntag(value, value); | 3576 __ SmiUntag(value, value); |
| 3550 __ Addu(at, | 3577 __ Addu(at, |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3723 generator.GenerateSlow(masm_, call_helper); | 3750 generator.GenerateSlow(masm_, call_helper); |
| 3724 | 3751 |
| 3725 __ bind(&done); | 3752 __ bind(&done); |
| 3726 context()->Plug(result); | 3753 context()->Plug(result); |
| 3727 } | 3754 } |
| 3728 | 3755 |
| 3729 | 3756 |
| 3730 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { | 3757 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) { |
| 3731 ZoneList<Expression*>* args = expr->arguments(); | 3758 ZoneList<Expression*>* args = expr->arguments(); |
| 3732 ASSERT_EQ(2, args->length()); | 3759 ASSERT_EQ(2, args->length()); |
| 3733 if (FLAG_new_string_add) { | 3760 VisitForStackValue(args->at(0)); |
| 3734 VisitForStackValue(args->at(0)); | 3761 VisitForAccumulatorValue(args->at(1)); |
| 3735 VisitForAccumulatorValue(args->at(1)); | |
| 3736 | 3762 |
| 3737 __ pop(a1); | 3763 __ pop(a1); |
| 3738 __ mov(a0, result_register()); // NewStringAddStub requires args in a0, a1. | 3764 __ mov(a0, result_register()); // StringAddStub requires args in a0, a1. |
| 3739 NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); | 3765 StringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED); |
| 3740 __ CallStub(&stub); | 3766 __ CallStub(&stub); |
| 3741 } else { | |
| 3742 VisitForStackValue(args->at(0)); | |
| 3743 VisitForStackValue(args->at(1)); | |
| 3744 | |
| 3745 StringAddStub stub(STRING_ADD_CHECK_BOTH); | |
| 3746 __ CallStub(&stub); | |
| 3747 } | |
| 3748 context()->Plug(v0); | 3767 context()->Plug(v0); |
| 3749 } | 3768 } |
| 3750 | 3769 |
| 3751 | 3770 |
| 3752 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { | 3771 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) { |
| 3753 ZoneList<Expression*>* args = expr->arguments(); | 3772 ZoneList<Expression*>* args = expr->arguments(); |
| 3754 ASSERT_EQ(2, args->length()); | 3773 ASSERT_EQ(2, args->length()); |
| 3755 | 3774 |
| 3756 VisitForStackValue(args->at(0)); | 3775 VisitForStackValue(args->at(0)); |
| 3757 VisitForStackValue(args->at(1)); | 3776 VisitForStackValue(args->at(1)); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3813 context()->Plug(v0); | 3832 context()->Plug(v0); |
| 3814 } | 3833 } |
| 3815 | 3834 |
| 3816 | 3835 |
| 3817 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { | 3836 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) { |
| 3818 RegExpConstructResultStub stub; | 3837 RegExpConstructResultStub stub; |
| 3819 ZoneList<Expression*>* args = expr->arguments(); | 3838 ZoneList<Expression*>* args = expr->arguments(); |
| 3820 ASSERT(args->length() == 3); | 3839 ASSERT(args->length() == 3); |
| 3821 VisitForStackValue(args->at(0)); | 3840 VisitForStackValue(args->at(0)); |
| 3822 VisitForStackValue(args->at(1)); | 3841 VisitForStackValue(args->at(1)); |
| 3823 VisitForStackValue(args->at(2)); | 3842 VisitForAccumulatorValue(args->at(2)); |
| 3843 __ mov(a0, result_register()); |
| 3844 __ pop(a1); |
| 3845 __ pop(a2); |
| 3824 __ CallStub(&stub); | 3846 __ CallStub(&stub); |
| 3825 context()->Plug(v0); | 3847 context()->Plug(v0); |
| 3826 } | 3848 } |
| 3827 | 3849 |
| 3828 | 3850 |
| 3829 void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { | 3851 void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) { |
| 3830 ZoneList<Expression*>* args = expr->arguments(); | 3852 ZoneList<Expression*>* args = expr->arguments(); |
| 3831 ASSERT_EQ(2, args->length()); | 3853 ASSERT_EQ(2, args->length()); |
| 3832 | 3854 |
| 3833 ASSERT_NE(NULL, args->at(0)->AsLiteral()); | 3855 ASSERT_NE(NULL, args->at(0)->AsLiteral()); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3873 __ bind(¬_found); | 3895 __ bind(¬_found); |
| 3874 // Call runtime to perform the lookup. | 3896 // Call runtime to perform the lookup. |
| 3875 __ Push(cache, key); | 3897 __ Push(cache, key); |
| 3876 __ CallRuntime(Runtime::kGetFromCache, 2); | 3898 __ CallRuntime(Runtime::kGetFromCache, 2); |
| 3877 | 3899 |
| 3878 __ bind(&done); | 3900 __ bind(&done); |
| 3879 context()->Plug(v0); | 3901 context()->Plug(v0); |
| 3880 } | 3902 } |
| 3881 | 3903 |
| 3882 | 3904 |
| 3883 void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) { | |
| 3884 ZoneList<Expression*>* args = expr->arguments(); | |
| 3885 ASSERT_EQ(2, args->length()); | |
| 3886 | |
| 3887 Register right = v0; | |
| 3888 Register left = a1; | |
| 3889 Register tmp = a2; | |
| 3890 Register tmp2 = a3; | |
| 3891 | |
| 3892 VisitForStackValue(args->at(0)); | |
| 3893 VisitForAccumulatorValue(args->at(1)); // Result (right) in v0. | |
| 3894 __ pop(left); | |
| 3895 | |
| 3896 Label done, fail, ok; | |
| 3897 __ Branch(&ok, eq, left, Operand(right)); | |
| 3898 // Fail if either is a non-HeapObject. | |
| 3899 __ And(tmp, left, Operand(right)); | |
| 3900 __ JumpIfSmi(tmp, &fail); | |
| 3901 __ lw(tmp, FieldMemOperand(left, HeapObject::kMapOffset)); | |
| 3902 __ lbu(tmp2, FieldMemOperand(tmp, Map::kInstanceTypeOffset)); | |
| 3903 __ Branch(&fail, ne, tmp2, Operand(JS_REGEXP_TYPE)); | |
| 3904 __ lw(tmp2, FieldMemOperand(right, HeapObject::kMapOffset)); | |
| 3905 __ Branch(&fail, ne, tmp, Operand(tmp2)); | |
| 3906 __ lw(tmp, FieldMemOperand(left, JSRegExp::kDataOffset)); | |
| 3907 __ lw(tmp2, FieldMemOperand(right, JSRegExp::kDataOffset)); | |
| 3908 __ Branch(&ok, eq, tmp, Operand(tmp2)); | |
| 3909 __ bind(&fail); | |
| 3910 __ LoadRoot(v0, Heap::kFalseValueRootIndex); | |
| 3911 __ jmp(&done); | |
| 3912 __ bind(&ok); | |
| 3913 __ LoadRoot(v0, Heap::kTrueValueRootIndex); | |
| 3914 __ bind(&done); | |
| 3915 | |
| 3916 context()->Plug(v0); | |
| 3917 } | |
| 3918 | |
| 3919 | |
| 3920 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { | 3905 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) { |
| 3921 ZoneList<Expression*>* args = expr->arguments(); | 3906 ZoneList<Expression*>* args = expr->arguments(); |
| 3922 VisitForAccumulatorValue(args->at(0)); | 3907 VisitForAccumulatorValue(args->at(0)); |
| 3923 | 3908 |
| 3924 Label materialize_true, materialize_false; | 3909 Label materialize_true, materialize_false; |
| 3925 Label* if_true = NULL; | 3910 Label* if_true = NULL; |
| 3926 Label* if_false = NULL; | 3911 Label* if_false = NULL; |
| 3927 Label* fall_through = NULL; | 3912 Label* fall_through = NULL; |
| 3928 context()->PrepareTest(&materialize_true, &materialize_false, | 3913 context()->PrepareTest(&materialize_true, &materialize_false, |
| 3929 &if_true, &if_false, &fall_through); | 3914 &if_true, &if_false, &fall_through); |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4193 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 4178 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 4194 Handle<String> name = expr->name(); | 4179 Handle<String> name = expr->name(); |
| 4195 if (name->length() > 0 && name->Get(0) == '_') { | 4180 if (name->length() > 0 && name->Get(0) == '_') { |
| 4196 Comment cmnt(masm_, "[ InlineRuntimeCall"); | 4181 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
| 4197 EmitInlineRuntimeCall(expr); | 4182 EmitInlineRuntimeCall(expr); |
| 4198 return; | 4183 return; |
| 4199 } | 4184 } |
| 4200 | 4185 |
| 4201 Comment cmnt(masm_, "[ CallRuntime"); | 4186 Comment cmnt(masm_, "[ CallRuntime"); |
| 4202 ZoneList<Expression*>* args = expr->arguments(); | 4187 ZoneList<Expression*>* args = expr->arguments(); |
| 4188 int arg_count = args->length(); |
| 4203 | 4189 |
| 4204 if (expr->is_jsruntime()) { | 4190 if (expr->is_jsruntime()) { |
| 4205 // Prepare for calling JS runtime function. | 4191 // Push the builtins object as the receiver. |
| 4206 __ lw(a0, GlobalObjectOperand()); | 4192 __ lw(a0, GlobalObjectOperand()); |
| 4207 __ lw(a0, FieldMemOperand(a0, GlobalObject::kBuiltinsOffset)); | 4193 __ lw(a0, FieldMemOperand(a0, GlobalObject::kBuiltinsOffset)); |
| 4208 __ push(a0); | 4194 __ push(a0); |
| 4209 } | 4195 // Load the function from the receiver. |
| 4196 __ li(a2, Operand(expr->name())); |
| 4197 CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); |
| 4210 | 4198 |
| 4211 // Push the arguments ("left-to-right"). | 4199 // Push the target function under the receiver. |
| 4212 int arg_count = args->length(); | 4200 __ lw(at, MemOperand(sp, 0)); |
| 4213 for (int i = 0; i < arg_count; i++) { | 4201 __ push(at); |
| 4214 VisitForStackValue(args->at(i)); | 4202 __ sw(v0, MemOperand(sp, kPointerSize)); |
| 4215 } | |
| 4216 | 4203 |
| 4217 if (expr->is_jsruntime()) { | 4204 // Push the arguments ("left-to-right"). |
| 4218 // Call the JS runtime function. | 4205 int arg_count = args->length(); |
| 4219 __ li(a2, Operand(expr->name())); | 4206 for (int i = 0; i < arg_count; i++) { |
| 4220 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count); | 4207 VisitForStackValue(args->at(i)); |
| 4221 CallIC(ic, NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId()); | 4208 } |
| 4209 |
| 4210 // Record source position of the IC call. |
| 4211 SetSourcePosition(expr->position()); |
| 4212 CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS); |
| 4213 __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize)); |
| 4214 __ CallStub(&stub); |
| 4215 |
| 4222 // Restore context register. | 4216 // Restore context register. |
| 4223 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); | 4217 __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); |
| 4218 |
| 4219 context()->DropAndPlug(1, v0); |
| 4224 } else { | 4220 } else { |
| 4221 // Push the arguments ("left-to-right"). |
| 4222 for (int i = 0; i < arg_count; i++) { |
| 4223 VisitForStackValue(args->at(i)); |
| 4224 } |
| 4225 |
| 4225 // Call the C runtime function. | 4226 // Call the C runtime function. |
| 4226 __ CallRuntime(expr->function(), arg_count); | 4227 __ CallRuntime(expr->function(), arg_count); |
| 4228 context()->Plug(v0); |
| 4227 } | 4229 } |
| 4228 context()->Plug(v0); | |
| 4229 } | 4230 } |
| 4230 | 4231 |
| 4231 | 4232 |
| 4232 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { | 4233 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
| 4233 switch (expr->op()) { | 4234 switch (expr->op()) { |
| 4234 case Token::DELETE: { | 4235 case Token::DELETE: { |
| 4235 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); | 4236 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); |
| 4236 Property* property = expr->expression()->AsProperty(); | 4237 Property* property = expr->expression()->AsProperty(); |
| 4237 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 4238 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
| 4238 | 4239 |
| (...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4461 } | 4462 } |
| 4462 | 4463 |
| 4463 __ bind(&stub_call); | 4464 __ bind(&stub_call); |
| 4464 __ mov(a1, v0); | 4465 __ mov(a1, v0); |
| 4465 __ li(a0, Operand(Smi::FromInt(count_value))); | 4466 __ li(a0, Operand(Smi::FromInt(count_value))); |
| 4466 | 4467 |
| 4467 // Record position before stub call. | 4468 // Record position before stub call. |
| 4468 SetSourcePosition(expr->position()); | 4469 SetSourcePosition(expr->position()); |
| 4469 | 4470 |
| 4470 BinaryOpICStub stub(Token::ADD, NO_OVERWRITE); | 4471 BinaryOpICStub stub(Token::ADD, NO_OVERWRITE); |
| 4471 CallIC(stub.GetCode(isolate()), | 4472 CallIC(stub.GetCode(isolate()), expr->CountBinOpFeedbackId()); |
| 4472 NOT_CONTEXTUAL, | |
| 4473 expr->CountBinOpFeedbackId()); | |
| 4474 patch_site.EmitPatchInfo(); | 4473 patch_site.EmitPatchInfo(); |
| 4475 __ bind(&done); | 4474 __ bind(&done); |
| 4476 | 4475 |
| 4477 // Store the value returned in v0. | 4476 // Store the value returned in v0. |
| 4478 switch (assign_type) { | 4477 switch (assign_type) { |
| 4479 case VARIABLE: | 4478 case VARIABLE: |
| 4480 if (expr->is_postfix()) { | 4479 if (expr->is_postfix()) { |
| 4481 { EffectContext context(this); | 4480 { EffectContext context(this); |
| 4482 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 4481 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 4483 Token::ASSIGN); | 4482 Token::ASSIGN); |
| 4484 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4483 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4485 context.Plug(v0); | 4484 context.Plug(v0); |
| 4486 } | 4485 } |
| 4487 // For all contexts except EffectConstant we have the result on | 4486 // For all contexts except EffectConstant we have the result on |
| 4488 // top of the stack. | 4487 // top of the stack. |
| 4489 if (!context()->IsEffect()) { | 4488 if (!context()->IsEffect()) { |
| 4490 context()->PlugTOS(); | 4489 context()->PlugTOS(); |
| 4491 } | 4490 } |
| 4492 } else { | 4491 } else { |
| 4493 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), | 4492 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), |
| 4494 Token::ASSIGN); | 4493 Token::ASSIGN); |
| 4495 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4494 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4496 context()->Plug(v0); | 4495 context()->Plug(v0); |
| 4497 } | 4496 } |
| 4498 break; | 4497 break; |
| 4499 case NAMED_PROPERTY: { | 4498 case NAMED_PROPERTY: { |
| 4500 __ mov(a0, result_register()); // Value. | 4499 __ mov(a0, result_register()); // Value. |
| 4501 __ li(a2, Operand(prop->key()->AsLiteral()->value())); // Name. | 4500 __ li(a2, Operand(prop->key()->AsLiteral()->value())); // Name. |
| 4502 __ pop(a1); // Receiver. | 4501 __ pop(a1); // Receiver. |
| 4503 CallStoreIC(NOT_CONTEXTUAL, expr->CountStoreFeedbackId()); | 4502 CallStoreIC(expr->CountStoreFeedbackId()); |
| 4504 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4503 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4505 if (expr->is_postfix()) { | 4504 if (expr->is_postfix()) { |
| 4506 if (!context()->IsEffect()) { | 4505 if (!context()->IsEffect()) { |
| 4507 context()->PlugTOS(); | 4506 context()->PlugTOS(); |
| 4508 } | 4507 } |
| 4509 } else { | 4508 } else { |
| 4510 context()->Plug(v0); | 4509 context()->Plug(v0); |
| 4511 } | 4510 } |
| 4512 break; | 4511 break; |
| 4513 } | 4512 } |
| 4514 case KEYED_PROPERTY: { | 4513 case KEYED_PROPERTY: { |
| 4515 __ mov(a0, result_register()); // Value. | 4514 __ mov(a0, result_register()); // Value. |
| 4516 __ Pop(a2, a1); // a1 = key, a2 = receiver. | 4515 __ Pop(a2, a1); // a1 = key, a2 = receiver. |
| 4517 Handle<Code> ic = is_classic_mode() | 4516 Handle<Code> ic = is_classic_mode() |
| 4518 ? isolate()->builtins()->KeyedStoreIC_Initialize() | 4517 ? isolate()->builtins()->KeyedStoreIC_Initialize() |
| 4519 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); | 4518 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict(); |
| 4520 CallIC(ic, NOT_CONTEXTUAL, expr->CountStoreFeedbackId()); | 4519 CallIC(ic, expr->CountStoreFeedbackId()); |
| 4521 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); | 4520 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); |
| 4522 if (expr->is_postfix()) { | 4521 if (expr->is_postfix()) { |
| 4523 if (!context()->IsEffect()) { | 4522 if (!context()->IsEffect()) { |
| 4524 context()->PlugTOS(); | 4523 context()->PlugTOS(); |
| 4525 } | 4524 } |
| 4526 } else { | 4525 } else { |
| 4527 context()->Plug(v0); | 4526 context()->Plug(v0); |
| 4528 } | 4527 } |
| 4529 break; | 4528 break; |
| 4530 } | 4529 } |
| 4531 } | 4530 } |
| 4532 } | 4531 } |
| 4533 | 4532 |
| 4534 | 4533 |
| 4535 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { | 4534 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { |
| 4536 ASSERT(!context()->IsEffect()); | 4535 ASSERT(!context()->IsEffect()); |
| 4537 ASSERT(!context()->IsTest()); | 4536 ASSERT(!context()->IsTest()); |
| 4538 VariableProxy* proxy = expr->AsVariableProxy(); | 4537 VariableProxy* proxy = expr->AsVariableProxy(); |
| 4539 if (proxy != NULL && proxy->var()->IsUnallocated()) { | 4538 if (proxy != NULL && proxy->var()->IsUnallocated()) { |
| 4540 Comment cmnt(masm_, "Global variable"); | 4539 Comment cmnt(masm_, "[ Global variable"); |
| 4541 __ lw(a0, GlobalObjectOperand()); | 4540 __ lw(a0, GlobalObjectOperand()); |
| 4542 __ li(a2, Operand(proxy->name())); | 4541 __ li(a2, Operand(proxy->name())); |
| 4543 // Use a regular load, not a contextual load, to avoid a reference | 4542 // Use a regular load, not a contextual load, to avoid a reference |
| 4544 // error. | 4543 // error. |
| 4545 CallLoadIC(NOT_CONTEXTUAL); | 4544 CallLoadIC(NOT_CONTEXTUAL); |
| 4546 PrepareForBailout(expr, TOS_REG); | 4545 PrepareForBailout(expr, TOS_REG); |
| 4547 context()->Plug(v0); | 4546 context()->Plug(v0); |
| 4548 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { | 4547 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { |
| 4548 Comment cmnt(masm_, "[ Lookup slot"); |
| 4549 Label done, slow; | 4549 Label done, slow; |
| 4550 | 4550 |
| 4551 // Generate code for loading from variables potentially shadowed | 4551 // Generate code for loading from variables potentially shadowed |
| 4552 // by eval-introduced variables. | 4552 // by eval-introduced variables. |
| 4553 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); | 4553 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done); |
| 4554 | 4554 |
| 4555 __ bind(&slow); | 4555 __ bind(&slow); |
| 4556 __ li(a0, Operand(proxy->name())); | 4556 __ li(a0, Operand(proxy->name())); |
| 4557 __ Push(cp, a0); | 4557 __ Push(cp, a0); |
| 4558 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 4558 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4695 if (inline_smi_code) { | 4695 if (inline_smi_code) { |
| 4696 Label slow_case; | 4696 Label slow_case; |
| 4697 __ Or(a2, a0, Operand(a1)); | 4697 __ Or(a2, a0, Operand(a1)); |
| 4698 patch_site.EmitJumpIfNotSmi(a2, &slow_case); | 4698 patch_site.EmitJumpIfNotSmi(a2, &slow_case); |
| 4699 Split(cc, a1, Operand(a0), if_true, if_false, NULL); | 4699 Split(cc, a1, Operand(a0), if_true, if_false, NULL); |
| 4700 __ bind(&slow_case); | 4700 __ bind(&slow_case); |
| 4701 } | 4701 } |
| 4702 // Record position and call the compare IC. | 4702 // Record position and call the compare IC. |
| 4703 SetSourcePosition(expr->position()); | 4703 SetSourcePosition(expr->position()); |
| 4704 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); | 4704 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op); |
| 4705 CallIC(ic, NOT_CONTEXTUAL, expr->CompareOperationFeedbackId()); | 4705 CallIC(ic, expr->CompareOperationFeedbackId()); |
| 4706 patch_site.EmitPatchInfo(); | 4706 patch_site.EmitPatchInfo(); |
| 4707 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 4707 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 4708 Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through); | 4708 Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through); |
| 4709 } | 4709 } |
| 4710 } | 4710 } |
| 4711 | 4711 |
| 4712 // Convert the result of the comparison into one expected for this | 4712 // Convert the result of the comparison into one expected for this |
| 4713 // expression's context. | 4713 // expression's context. |
| 4714 context()->Plug(if_true, if_false); | 4714 context()->Plug(if_true, if_false); |
| 4715 } | 4715 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 4729 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); | 4729 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false); |
| 4730 __ mov(a0, result_register()); | 4730 __ mov(a0, result_register()); |
| 4731 if (expr->op() == Token::EQ_STRICT) { | 4731 if (expr->op() == Token::EQ_STRICT) { |
| 4732 Heap::RootListIndex nil_value = nil == kNullValue ? | 4732 Heap::RootListIndex nil_value = nil == kNullValue ? |
| 4733 Heap::kNullValueRootIndex : | 4733 Heap::kNullValueRootIndex : |
| 4734 Heap::kUndefinedValueRootIndex; | 4734 Heap::kUndefinedValueRootIndex; |
| 4735 __ LoadRoot(a1, nil_value); | 4735 __ LoadRoot(a1, nil_value); |
| 4736 Split(eq, a0, Operand(a1), if_true, if_false, fall_through); | 4736 Split(eq, a0, Operand(a1), if_true, if_false, fall_through); |
| 4737 } else { | 4737 } else { |
| 4738 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); | 4738 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil); |
| 4739 CallIC(ic, NOT_CONTEXTUAL, expr->CompareOperationFeedbackId()); | 4739 CallIC(ic, expr->CompareOperationFeedbackId()); |
| 4740 Split(ne, v0, Operand(zero_reg), if_true, if_false, fall_through); | 4740 Split(ne, v0, Operand(zero_reg), if_true, if_false, fall_through); |
| 4741 } | 4741 } |
| 4742 context()->Plug(if_true, if_false); | 4742 context()->Plug(if_true, if_false); |
| 4743 } | 4743 } |
| 4744 | 4744 |
| 4745 | 4745 |
| 4746 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { | 4746 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) { |
| 4747 __ lw(v0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 4747 __ lw(v0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 4748 context()->Plug(v0); | 4748 context()->Plug(v0); |
| 4749 } | 4749 } |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4967 Assembler::target_address_at(pc_immediate_load_address)) == | 4967 Assembler::target_address_at(pc_immediate_load_address)) == |
| 4968 reinterpret_cast<uint32_t>( | 4968 reinterpret_cast<uint32_t>( |
| 4969 isolate->builtins()->OsrAfterStackCheck()->entry())); | 4969 isolate->builtins()->OsrAfterStackCheck()->entry())); |
| 4970 return OSR_AFTER_STACK_CHECK; | 4970 return OSR_AFTER_STACK_CHECK; |
| 4971 } | 4971 } |
| 4972 | 4972 |
| 4973 | 4973 |
| 4974 } } // namespace v8::internal | 4974 } } // namespace v8::internal |
| 4975 | 4975 |
| 4976 #endif // V8_TARGET_ARCH_MIPS | 4976 #endif // V8_TARGET_ARCH_MIPS |
| OLD | NEW |