| 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 |