OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #if V8_TARGET_ARCH_MIPS64 | 5 #if V8_TARGET_ARCH_MIPS64 |
6 | 6 |
7 #include "src/ic/handler-compiler.h" | 7 #include "src/ic/handler-compiler.h" |
8 | 8 |
9 #include "src/api-arguments.h" | 9 #include "src/api-arguments.h" |
10 #include "src/field-type.h" | 10 #include "src/field-type.h" |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 // Save context and value registers, so we can restore them later. | 43 // Save context and value registers, so we can restore them later. |
44 __ Push(cp, value()); | 44 __ Push(cp, value()); |
45 | 45 |
46 if (accessor_index >= 0) { | 46 if (accessor_index >= 0) { |
47 DCHECK(!holder.is(scratch)); | 47 DCHECK(!holder.is(scratch)); |
48 DCHECK(!receiver.is(scratch)); | 48 DCHECK(!receiver.is(scratch)); |
49 DCHECK(!value().is(scratch)); | 49 DCHECK(!value().is(scratch)); |
50 // Call the JavaScript setter with receiver and value on the stack. | 50 // Call the JavaScript setter with receiver and value on the stack. |
51 if (map->IsJSGlobalObjectMap()) { | 51 if (map->IsJSGlobalObjectMap()) { |
52 // Swap in the global receiver. | 52 // Swap in the global receiver. |
53 __ ld(scratch, | 53 __ Ld(scratch, |
54 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); | 54 FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset)); |
55 receiver = scratch; | 55 receiver = scratch; |
56 } | 56 } |
57 __ Push(receiver, value()); | 57 __ Push(receiver, value()); |
58 __ LoadAccessor(a1, holder, accessor_index, ACCESSOR_SETTER); | 58 __ LoadAccessor(a1, holder, accessor_index, ACCESSOR_SETTER); |
59 __ li(a0, Operand(1)); | 59 __ li(a0, Operand(1)); |
60 __ Call(masm->isolate()->builtins()->CallFunction( | 60 __ Call(masm->isolate()->builtins()->CallFunction( |
61 ConvertReceiverMode::kNotNullOrUndefined), | 61 ConvertReceiverMode::kNotNullOrUndefined), |
62 RelocInfo::CODE_TARGET); | 62 RelocInfo::CODE_TARGET); |
63 } else { | 63 } else { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); | 108 __ IncrementCounter(counters->negative_lookups(), 1, scratch0, scratch1); |
109 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); | 109 __ IncrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); |
110 | 110 |
111 Label done; | 111 Label done; |
112 | 112 |
113 const int kInterceptorOrAccessCheckNeededMask = | 113 const int kInterceptorOrAccessCheckNeededMask = |
114 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); | 114 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); |
115 | 115 |
116 // Bail out if the receiver has a named interceptor or requires access checks. | 116 // Bail out if the receiver has a named interceptor or requires access checks. |
117 Register map = scratch1; | 117 Register map = scratch1; |
118 __ ld(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 118 __ Ld(map, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
119 __ lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset)); | 119 __ Lbu(scratch0, FieldMemOperand(map, Map::kBitFieldOffset)); |
120 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask)); | 120 __ And(scratch0, scratch0, Operand(kInterceptorOrAccessCheckNeededMask)); |
121 __ Branch(miss_label, ne, scratch0, Operand(zero_reg)); | 121 __ Branch(miss_label, ne, scratch0, Operand(zero_reg)); |
122 | 122 |
123 // Check that receiver is a JSObject. | 123 // Check that receiver is a JSObject. |
124 __ lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset)); | 124 __ Lbu(scratch0, FieldMemOperand(map, Map::kInstanceTypeOffset)); |
125 __ Branch(miss_label, lt, scratch0, Operand(FIRST_JS_RECEIVER_TYPE)); | 125 __ Branch(miss_label, lt, scratch0, Operand(FIRST_JS_RECEIVER_TYPE)); |
126 | 126 |
127 // Load properties array. | 127 // Load properties array. |
128 Register properties = scratch0; | 128 Register properties = scratch0; |
129 __ ld(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 129 __ Ld(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
130 // Check that the properties array is a dictionary. | 130 // Check that the properties array is a dictionary. |
131 __ ld(map, FieldMemOperand(properties, HeapObject::kMapOffset)); | 131 __ Ld(map, FieldMemOperand(properties, HeapObject::kMapOffset)); |
132 Register tmp = properties; | 132 Register tmp = properties; |
133 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex); | 133 __ LoadRoot(tmp, Heap::kHashTableMapRootIndex); |
134 __ Branch(miss_label, ne, map, Operand(tmp)); | 134 __ Branch(miss_label, ne, map, Operand(tmp)); |
135 | 135 |
136 // Restore the temporarily used register. | 136 // Restore the temporarily used register. |
137 __ ld(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); | 137 __ Ld(properties, FieldMemOperand(receiver, JSObject::kPropertiesOffset)); |
138 | |
139 | 138 |
140 NameDictionaryLookupStub::GenerateNegativeLookup( | 139 NameDictionaryLookupStub::GenerateNegativeLookup( |
141 masm, miss_label, &done, receiver, properties, name, scratch1); | 140 masm, miss_label, &done, receiver, properties, name, scratch1); |
142 __ bind(&done); | 141 __ bind(&done); |
143 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); | 142 __ DecrementCounter(counters->negative_lookups_miss(), 1, scratch0, scratch1); |
144 } | 143 } |
145 | 144 |
146 // Generate code to check that a global property cell is empty. Create | 145 // Generate code to check that a global property cell is empty. Create |
147 // the property cell at compilation time if no cell exists for the | 146 // the property cell at compilation time if no cell exists for the |
148 // property. | 147 // property. |
149 void PropertyHandlerCompiler::GenerateCheckPropertyCell( | 148 void PropertyHandlerCompiler::GenerateCheckPropertyCell( |
150 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, | 149 MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name, |
151 Register scratch, Label* miss) { | 150 Register scratch, Label* miss) { |
152 Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell( | 151 Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell( |
153 global, name, PropertyCellType::kInvalidated); | 152 global, name, PropertyCellType::kInvalidated); |
154 Isolate* isolate = masm->isolate(); | 153 Isolate* isolate = masm->isolate(); |
155 DCHECK(cell->value()->IsTheHole(isolate)); | 154 DCHECK(cell->value()->IsTheHole(isolate)); |
156 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell); | 155 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell); |
157 __ LoadWeakValue(scratch, weak_cell, miss); | 156 __ LoadWeakValue(scratch, weak_cell, miss); |
158 __ ld(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset)); | 157 __ Ld(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset)); |
159 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); | 158 __ LoadRoot(at, Heap::kTheHoleValueRootIndex); |
160 __ Branch(miss, ne, scratch, Operand(at)); | 159 __ Branch(miss, ne, scratch, Operand(at)); |
161 } | 160 } |
162 | 161 |
163 // Generate call to api function. | 162 // Generate call to api function. |
164 void PropertyHandlerCompiler::GenerateApiAccessorCall( | 163 void PropertyHandlerCompiler::GenerateApiAccessorCall( |
165 MacroAssembler* masm, const CallOptimization& optimization, | 164 MacroAssembler* masm, const CallOptimization& optimization, |
166 Handle<Map> receiver_map, Register receiver, Register scratch_in, | 165 Handle<Map> receiver_map, Register receiver, Register scratch_in, |
167 bool is_store, Register store_parameter, Register accessor_holder, | 166 bool is_store, Register store_parameter, Register accessor_holder, |
168 int accessor_index) { | 167 int accessor_index) { |
(...skipping 21 matching lines...) Expand all Loading... |
190 // Put holder in place. | 189 // Put holder in place. |
191 CallOptimization::HolderLookup holder_lookup; | 190 CallOptimization::HolderLookup holder_lookup; |
192 int holder_depth = 0; | 191 int holder_depth = 0; |
193 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup, | 192 optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup, |
194 &holder_depth); | 193 &holder_depth); |
195 switch (holder_lookup) { | 194 switch (holder_lookup) { |
196 case CallOptimization::kHolderIsReceiver: | 195 case CallOptimization::kHolderIsReceiver: |
197 __ Move(holder, receiver); | 196 __ Move(holder, receiver); |
198 break; | 197 break; |
199 case CallOptimization::kHolderFound: | 198 case CallOptimization::kHolderFound: |
200 __ ld(holder, FieldMemOperand(receiver, HeapObject::kMapOffset)); | 199 __ Ld(holder, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
201 __ ld(holder, FieldMemOperand(holder, Map::kPrototypeOffset)); | 200 __ Ld(holder, FieldMemOperand(holder, Map::kPrototypeOffset)); |
202 for (int i = 1; i < holder_depth; i++) { | 201 for (int i = 1; i < holder_depth; i++) { |
203 __ ld(holder, FieldMemOperand(holder, HeapObject::kMapOffset)); | 202 __ Ld(holder, FieldMemOperand(holder, HeapObject::kMapOffset)); |
204 __ ld(holder, FieldMemOperand(holder, Map::kPrototypeOffset)); | 203 __ Ld(holder, FieldMemOperand(holder, Map::kPrototypeOffset)); |
205 } | 204 } |
206 break; | 205 break; |
207 case CallOptimization::kHolderNotFound: | 206 case CallOptimization::kHolderNotFound: |
208 UNREACHABLE(); | 207 UNREACHABLE(); |
209 break; | 208 break; |
210 } | 209 } |
211 | 210 |
212 Isolate* isolate = masm->isolate(); | 211 Isolate* isolate = masm->isolate(); |
213 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); | 212 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
214 bool call_data_undefined = false; | 213 bool call_data_undefined = false; |
215 // Put call data in place. | 214 // Put call data in place. |
216 if (api_call_info->data()->IsUndefined(isolate)) { | 215 if (api_call_info->data()->IsUndefined(isolate)) { |
217 call_data_undefined = true; | 216 call_data_undefined = true; |
218 __ LoadRoot(data, Heap::kUndefinedValueRootIndex); | 217 __ LoadRoot(data, Heap::kUndefinedValueRootIndex); |
219 } else { | 218 } else { |
220 if (optimization.is_constant_call()) { | 219 if (optimization.is_constant_call()) { |
221 __ ld(data, | 220 __ Ld(data, |
222 FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset)); | 221 FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset)); |
223 __ ld(data, | 222 __ Ld(data, |
224 FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset)); | 223 FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset)); |
225 __ ld(data, FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset)); | 224 __ Ld(data, FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset)); |
226 } else { | 225 } else { |
227 __ ld(data, | 226 __ Ld(data, |
228 FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset)); | 227 FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset)); |
229 } | 228 } |
230 __ ld(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset)); | 229 __ Ld(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset)); |
231 } | 230 } |
232 | 231 |
233 // Put api_function_address in place. | 232 // Put api_function_address in place. |
234 Address function_address = v8::ToCData<Address>(api_call_info->callback()); | 233 Address function_address = v8::ToCData<Address>(api_call_info->callback()); |
235 ApiFunction fun(function_address); | 234 ApiFunction fun(function_address); |
236 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; | 235 ExternalReference::Type type = ExternalReference::DIRECT_API_CALL; |
237 ExternalReference ref = ExternalReference(&fun, type, masm->isolate()); | 236 ExternalReference ref = ExternalReference(&fun, type, masm->isolate()); |
238 __ li(api_function_address, Operand(ref)); | 237 __ li(api_function_address, Operand(ref)); |
239 | 238 |
240 // Jump to stub. | 239 // Jump to stub. |
(...skipping 12 matching lines...) Expand all Loading... |
253 __ bind(label); | 252 __ bind(label); |
254 __ li(this->name(), Operand(name)); | 253 __ li(this->name(), Operand(name)); |
255 } | 254 } |
256 } | 255 } |
257 | 256 |
258 void PropertyHandlerCompiler::GenerateAccessCheck( | 257 void PropertyHandlerCompiler::GenerateAccessCheck( |
259 Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2, | 258 Handle<WeakCell> native_context_cell, Register scratch1, Register scratch2, |
260 Label* miss, bool compare_native_contexts_only) { | 259 Label* miss, bool compare_native_contexts_only) { |
261 Label done; | 260 Label done; |
262 // Load current native context. | 261 // Load current native context. |
263 __ ld(scratch1, NativeContextMemOperand()); | 262 __ Ld(scratch1, NativeContextMemOperand()); |
264 // Load expected native context. | 263 // Load expected native context. |
265 __ LoadWeakValue(scratch2, native_context_cell, miss); | 264 __ LoadWeakValue(scratch2, native_context_cell, miss); |
266 | 265 |
267 if (!compare_native_contexts_only) { | 266 if (!compare_native_contexts_only) { |
268 __ Branch(&done, eq, scratch1, Operand(scratch2)); | 267 __ Branch(&done, eq, scratch1, Operand(scratch2)); |
269 | 268 |
270 // Compare security tokens of current and expected native contexts. | 269 // Compare security tokens of current and expected native contexts. |
271 __ ld(scratch1, ContextMemOperand(scratch1, Context::SECURITY_TOKEN_INDEX)); | 270 __ Ld(scratch1, ContextMemOperand(scratch1, Context::SECURITY_TOKEN_INDEX)); |
272 __ ld(scratch2, ContextMemOperand(scratch2, Context::SECURITY_TOKEN_INDEX)); | 271 __ Ld(scratch2, ContextMemOperand(scratch2, Context::SECURITY_TOKEN_INDEX)); |
273 } | 272 } |
274 __ Branch(miss, ne, scratch1, Operand(scratch2)); | 273 __ Branch(miss, ne, scratch1, Operand(scratch2)); |
275 | 274 |
276 __ bind(&done); | 275 __ bind(&done); |
277 } | 276 } |
278 | 277 |
279 Register PropertyHandlerCompiler::CheckPrototypes( | 278 Register PropertyHandlerCompiler::CheckPrototypes( |
280 Register object_reg, Register holder_reg, Register scratch1, | 279 Register object_reg, Register holder_reg, Register scratch1, |
281 Register scratch2, Handle<Name> name, Label* miss) { | 280 Register scratch2, Handle<Name> name, Label* miss) { |
282 Handle<Map> receiver_map = map(); | 281 Handle<Map> receiver_map = map(); |
283 | 282 |
284 // Make sure there's no overlap between holder and object registers. | 283 // Make sure there's no overlap between holder and object registers. |
285 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); | 284 DCHECK(!scratch1.is(object_reg) && !scratch1.is(holder_reg)); |
286 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && | 285 DCHECK(!scratch2.is(object_reg) && !scratch2.is(holder_reg) && |
287 !scratch2.is(scratch1)); | 286 !scratch2.is(scratch1)); |
288 | 287 |
289 Handle<Cell> validity_cell = | 288 Handle<Cell> validity_cell = |
290 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); | 289 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate()); |
291 if (!validity_cell.is_null()) { | 290 if (!validity_cell.is_null()) { |
292 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value()); | 291 DCHECK_EQ(Smi::FromInt(Map::kPrototypeChainValid), validity_cell->value()); |
293 __ li(scratch1, Operand(validity_cell)); | 292 __ li(scratch1, Operand(validity_cell)); |
294 __ ld(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); | 293 __ Ld(scratch1, FieldMemOperand(scratch1, Cell::kValueOffset)); |
295 __ Branch(miss, ne, scratch1, | 294 __ Branch(miss, ne, scratch1, |
296 Operand(Smi::FromInt(Map::kPrototypeChainValid))); | 295 Operand(Smi::FromInt(Map::kPrototypeChainValid))); |
297 } | 296 } |
298 | 297 |
299 // Keep track of the current object in register reg. | 298 // Keep track of the current object in register reg. |
300 Register reg = object_reg; | 299 Register reg = object_reg; |
301 int depth = 0; | 300 int depth = 0; |
302 | 301 |
303 Handle<JSObject> current = Handle<JSObject>::null(); | 302 Handle<JSObject> current = Handle<JSObject>::null(); |
304 if (receiver_map->IsJSGlobalObjectMap()) { | 303 if (receiver_map->IsJSGlobalObjectMap()) { |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
412 Register NamedStoreHandlerCompiler::value() { | 411 Register NamedStoreHandlerCompiler::value() { |
413 return StoreDescriptor::ValueRegister(); | 412 return StoreDescriptor::ValueRegister(); |
414 } | 413 } |
415 | 414 |
416 | 415 |
417 #undef __ | 416 #undef __ |
418 } // namespace internal | 417 } // namespace internal |
419 } // namespace v8 | 418 } // namespace v8 |
420 | 419 |
421 #endif // V8_TARGET_ARCH_MIPS64 | 420 #endif // V8_TARGET_ARCH_MIPS64 |
OLD | NEW |