| OLD | NEW |
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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 #include "src/fast-accessor-assembler.h" | 5 #include "src/fast-accessor-assembler.h" |
| 6 | 6 |
| 7 #include "src/base/logging.h" | 7 #include "src/base/logging.h" |
| 8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
| 9 #include "src/code-stubs.h" // For CallApiCallbackStub. | 9 #include "src/code-stubs.h" // For CallApiCallbackStub. |
| 10 #include "src/handles-inl.h" | 10 #include "src/handles-inl.h" |
| 11 #include "src/objects.h" // For FAA::LoadInternalField impl. | 11 #include "src/objects.h" // For FAA::LoadInternalField impl. |
| 12 | 12 |
| 13 using v8::internal::compiler::Node; | |
| 14 | |
| 15 namespace v8 { | 13 namespace v8 { |
| 16 namespace internal { | 14 namespace internal { |
| 17 | 15 |
| 16 using compiler::Node; |
| 17 using compiler::CodeAssemblerLabel; |
| 18 using compiler::CodeAssemblerVariable; |
| 19 |
| 18 FastAccessorAssembler::FastAccessorAssembler(Isolate* isolate) | 20 FastAccessorAssembler::FastAccessorAssembler(Isolate* isolate) |
| 19 : zone_(isolate->allocator(), ZONE_NAME), | 21 : zone_(isolate->allocator(), ZONE_NAME), |
| 20 isolate_(isolate), | 22 isolate_(isolate), |
| 21 assembler_state_(isolate, zone(), 1, Code::ComputeFlags(Code::STUB), | 23 assembler_state_(new compiler::CodeAssemblerState( |
| 22 "FastAccessorAssembler"), | 24 isolate, zone(), 1, Code::ComputeFlags(Code::STUB), |
| 23 assembler_(new CodeStubAssembler(&assembler_state_)), | 25 "FastAccessorAssembler")), |
| 26 assembler_(new CodeStubAssembler(assembler_state_.get())), |
| 24 state_(kBuilding) {} | 27 state_(kBuilding) {} |
| 25 | 28 |
| 26 FastAccessorAssembler::~FastAccessorAssembler() { Clear(); } | 29 FastAccessorAssembler::~FastAccessorAssembler() { Clear(); } |
| 27 | 30 |
| 28 FastAccessorAssembler::ValueId FastAccessorAssembler::IntegerConstant( | 31 FastAccessorAssembler::ValueId FastAccessorAssembler::IntegerConstant( |
| 29 int const_value) { | 32 int const_value) { |
| 30 CHECK_EQ(kBuilding, state_); | 33 CHECK_EQ(kBuilding, state_); |
| 31 return FromRaw(assembler_->NumberConstant(const_value)); | 34 return FromRaw(assembler_->NumberConstant(const_value)); |
| 32 } | 35 } |
| 33 | 36 |
| 34 FastAccessorAssembler::ValueId FastAccessorAssembler::GetReceiver() { | 37 FastAccessorAssembler::ValueId FastAccessorAssembler::GetReceiver() { |
| 35 CHECK_EQ(kBuilding, state_); | 38 CHECK_EQ(kBuilding, state_); |
| 36 | 39 |
| 37 // For JS functions, the receiver is parameter 0. | 40 // For JS functions, the receiver is parameter 0. |
| 38 return FromRaw(assembler_->Parameter(0)); | 41 return FromRaw(assembler_->Parameter(0)); |
| 39 } | 42 } |
| 40 | 43 |
| 41 FastAccessorAssembler::ValueId FastAccessorAssembler::LoadInternalField( | 44 FastAccessorAssembler::ValueId FastAccessorAssembler::LoadInternalField( |
| 42 ValueId value, int field_no) { | 45 ValueId value_id, int field_no) { |
| 43 CHECK_EQ(kBuilding, state_); | 46 CHECK_EQ(kBuilding, state_); |
| 44 | 47 |
| 45 CodeStubAssembler::Variable result(assembler_.get(), | 48 CodeAssemblerVariable result(assembler_.get(), |
| 46 MachineRepresentation::kTagged); | 49 MachineRepresentation::kTagged); |
| 47 LabelId is_not_jsobject = MakeLabel(); | 50 LabelId is_not_jsobject = MakeLabel(); |
| 48 CodeStubAssembler::Label merge(assembler_.get(), &result); | 51 CodeAssemblerLabel merge(assembler_.get(), &result); |
| 49 | 52 |
| 50 CheckIsJSObjectOrJump(value, is_not_jsobject); | 53 CheckIsJSObjectOrJump(value_id, is_not_jsobject); |
| 51 | 54 |
| 52 Node* internal_field = assembler_->LoadObjectField( | 55 Node* internal_field = assembler_->LoadObjectField( |
| 53 FromId(value), JSObject::kHeaderSize + kPointerSize * field_no, | 56 FromId(value_id), JSObject::kHeaderSize + kPointerSize * field_no); |
| 54 MachineType::Pointer()); | |
| 55 | 57 |
| 56 result.Bind(internal_field); | 58 result.Bind(internal_field); |
| 57 assembler_->Goto(&merge); | 59 assembler_->Goto(&merge); |
| 58 | 60 |
| 59 // Return null, mimicking the C++ counterpart. | 61 // Return null, mimicking the C++ counterpart. |
| 60 SetLabel(is_not_jsobject); | 62 SetLabel(is_not_jsobject); |
| 61 result.Bind(assembler_->NullConstant()); | 63 result.Bind(assembler_->NullConstant()); |
| 62 assembler_->Goto(&merge); | 64 assembler_->Goto(&merge); |
| 63 | 65 |
| 64 // Return. | 66 // Return. |
| 65 assembler_->Bind(&merge); | 67 assembler_->Bind(&merge); |
| 66 return FromRaw(result.value()); | 68 return FromRaw(result.value()); |
| 67 } | 69 } |
| 68 | 70 |
| 69 FastAccessorAssembler::ValueId | 71 FastAccessorAssembler::ValueId |
| 70 FastAccessorAssembler::LoadInternalFieldUnchecked(ValueId value, int field_no) { | 72 FastAccessorAssembler::LoadInternalFieldUnchecked(ValueId value_id, |
| 73 int field_no) { |
| 71 CHECK_EQ(kBuilding, state_); | 74 CHECK_EQ(kBuilding, state_); |
| 72 | 75 |
| 73 // Defensive debug checks. | 76 // Defensive debug checks. |
| 74 if (FLAG_debug_code) { | 77 if (FLAG_debug_code) { |
| 75 LabelId is_jsobject = MakeLabel(); | 78 LabelId is_jsobject = MakeLabel(); |
| 76 LabelId is_not_jsobject = MakeLabel(); | 79 LabelId is_not_jsobject = MakeLabel(); |
| 77 CheckIsJSObjectOrJump(value, is_not_jsobject); | 80 CheckIsJSObjectOrJump(value_id, is_not_jsobject); |
| 78 assembler_->Goto(FromId(is_jsobject)); | 81 assembler_->Goto(FromId(is_jsobject)); |
| 79 | 82 |
| 80 SetLabel(is_not_jsobject); | 83 SetLabel(is_not_jsobject); |
| 81 assembler_->DebugBreak(); | 84 assembler_->DebugBreak(); |
| 82 assembler_->Goto(FromId(is_jsobject)); | 85 assembler_->Goto(FromId(is_jsobject)); |
| 83 | 86 |
| 84 SetLabel(is_jsobject); | 87 SetLabel(is_jsobject); |
| 85 } | 88 } |
| 86 | 89 |
| 87 Node* result = assembler_->LoadObjectField( | 90 Node* result = assembler_->LoadObjectField( |
| 88 FromId(value), JSObject::kHeaderSize + kPointerSize * field_no, | 91 FromId(value_id), JSObject::kHeaderSize + kPointerSize * field_no); |
| 89 MachineType::Pointer()); | |
| 90 | 92 |
| 91 return FromRaw(result); | 93 return FromRaw(result); |
| 92 } | 94 } |
| 93 | 95 |
| 94 FastAccessorAssembler::ValueId FastAccessorAssembler::LoadValue(ValueId value, | 96 FastAccessorAssembler::ValueId FastAccessorAssembler::LoadValue( |
| 95 int offset) { | 97 ValueId value_id, int offset) { |
| 96 CHECK_EQ(kBuilding, state_); | 98 CHECK_EQ(kBuilding, state_); |
| 97 return FromRaw(assembler_->LoadBufferObject(FromId(value), offset, | 99 return FromRaw(assembler_->LoadBufferObject(FromId(value_id), offset, |
| 98 MachineType::IntPtr())); | 100 MachineType::IntPtr())); |
| 99 } | 101 } |
| 100 | 102 |
| 101 FastAccessorAssembler::ValueId FastAccessorAssembler::LoadObject(ValueId value, | 103 FastAccessorAssembler::ValueId FastAccessorAssembler::LoadObject( |
| 102 int offset) { | 104 ValueId value_id, int offset) { |
| 103 CHECK_EQ(kBuilding, state_); | 105 CHECK_EQ(kBuilding, state_); |
| 104 return FromRaw(assembler_->LoadBufferObject( | 106 return FromRaw(assembler_->LoadBufferObject( |
| 105 assembler_->LoadBufferObject(FromId(value), offset, | 107 assembler_->LoadBufferObject(FromId(value_id), offset), 0, |
| 106 MachineType::Pointer()), | 108 MachineType::AnyTagged())); |
| 107 0, MachineType::AnyTagged())); | |
| 108 } | 109 } |
| 109 | 110 |
| 110 FastAccessorAssembler::ValueId FastAccessorAssembler::ToSmi(ValueId value) { | 111 FastAccessorAssembler::ValueId FastAccessorAssembler::ToSmi(ValueId value_id) { |
| 111 CHECK_EQ(kBuilding, state_); | 112 CHECK_EQ(kBuilding, state_); |
| 112 return FromRaw(assembler_->SmiTag(FromId(value))); | 113 return FromRaw(assembler_->SmiTag(FromId(value_id))); |
| 113 } | 114 } |
| 114 | 115 |
| 115 void FastAccessorAssembler::ReturnValue(ValueId value) { | 116 void FastAccessorAssembler::ReturnValue(ValueId value_id) { |
| 116 CHECK_EQ(kBuilding, state_); | 117 CHECK_EQ(kBuilding, state_); |
| 117 assembler_->Return(FromId(value)); | 118 assembler_->Return(FromId(value_id)); |
| 118 } | 119 } |
| 119 | 120 |
| 120 void FastAccessorAssembler::CheckFlagSetOrReturnNull(ValueId value, int mask) { | 121 void FastAccessorAssembler::CheckFlagSetOrReturnNull(ValueId value_id, |
| 122 int mask) { |
| 121 CHECK_EQ(kBuilding, state_); | 123 CHECK_EQ(kBuilding, state_); |
| 122 CodeStubAssembler::Label pass(assembler_.get()); | 124 CodeAssemblerLabel pass(assembler_.get()); |
| 123 CodeStubAssembler::Label fail(assembler_.get()); | 125 CodeAssemblerLabel fail(assembler_.get()); |
| 126 Node* value = FromId(value_id); |
| 124 assembler_->Branch( | 127 assembler_->Branch( |
| 125 assembler_->Word32Equal( | 128 assembler_->IsSetWord(assembler_->BitcastTaggedToWord(value), mask), |
| 126 assembler_->Word32And(FromId(value), assembler_->Int32Constant(mask)), | 129 &pass, &fail); |
| 127 assembler_->Int32Constant(0)), | |
| 128 &fail, &pass); | |
| 129 assembler_->Bind(&fail); | 130 assembler_->Bind(&fail); |
| 130 assembler_->Return(assembler_->NullConstant()); | 131 assembler_->Return(assembler_->NullConstant()); |
| 131 assembler_->Bind(&pass); | 132 assembler_->Bind(&pass); |
| 132 } | 133 } |
| 133 | 134 |
| 134 void FastAccessorAssembler::CheckNotZeroOrReturnNull(ValueId value) { | 135 void FastAccessorAssembler::CheckNotZeroOrReturnNull(ValueId value_id) { |
| 135 CHECK_EQ(kBuilding, state_); | 136 CHECK_EQ(kBuilding, state_); |
| 136 CodeStubAssembler::Label is_null(assembler_.get()); | 137 CodeAssemblerLabel is_null(assembler_.get()); |
| 137 CodeStubAssembler::Label not_null(assembler_.get()); | 138 CodeAssemblerLabel not_null(assembler_.get()); |
| 138 assembler_->Branch( | 139 assembler_->Branch( |
| 139 assembler_->WordEqual(FromId(value), assembler_->IntPtrConstant(0)), | 140 assembler_->WordEqual(FromId(value_id), assembler_->SmiConstant(0)), |
| 140 &is_null, ¬_null); | 141 &is_null, ¬_null); |
| 141 assembler_->Bind(&is_null); | 142 assembler_->Bind(&is_null); |
| 142 assembler_->Return(assembler_->NullConstant()); | 143 assembler_->Return(assembler_->NullConstant()); |
| 143 assembler_->Bind(¬_null); | 144 assembler_->Bind(¬_null); |
| 144 } | 145 } |
| 145 | 146 |
| 146 FastAccessorAssembler::LabelId FastAccessorAssembler::MakeLabel() { | 147 FastAccessorAssembler::LabelId FastAccessorAssembler::MakeLabel() { |
| 147 CHECK_EQ(kBuilding, state_); | 148 CHECK_EQ(kBuilding, state_); |
| 148 return FromRaw(new CodeStubAssembler::Label(assembler_.get())); | 149 return FromRaw(new CodeAssemblerLabel(assembler_.get())); |
| 149 } | 150 } |
| 150 | 151 |
| 151 void FastAccessorAssembler::SetLabel(LabelId label_id) { | 152 void FastAccessorAssembler::SetLabel(LabelId label_id) { |
| 152 CHECK_EQ(kBuilding, state_); | 153 CHECK_EQ(kBuilding, state_); |
| 153 assembler_->Bind(FromId(label_id)); | 154 assembler_->Bind(FromId(label_id)); |
| 154 } | 155 } |
| 155 | 156 |
| 156 void FastAccessorAssembler::Goto(LabelId label_id) { | 157 void FastAccessorAssembler::Goto(LabelId label_id) { |
| 157 CHECK_EQ(kBuilding, state_); | 158 CHECK_EQ(kBuilding, state_); |
| 158 assembler_->Goto(FromId(label_id)); | 159 assembler_->Goto(FromId(label_id)); |
| 159 } | 160 } |
| 160 | 161 |
| 161 void FastAccessorAssembler::CheckNotZeroOrJump(ValueId value_id, | 162 void FastAccessorAssembler::CheckNotZeroOrJump(ValueId value_id, |
| 162 LabelId label_id) { | 163 LabelId label_id) { |
| 163 CHECK_EQ(kBuilding, state_); | 164 CHECK_EQ(kBuilding, state_); |
| 164 CodeStubAssembler::Label pass(assembler_.get()); | 165 CodeAssemblerLabel pass(assembler_.get()); |
| 165 assembler_->Branch( | 166 assembler_->Branch( |
| 166 assembler_->WordEqual(FromId(value_id), assembler_->IntPtrConstant(0)), | 167 assembler_->WordEqual(FromId(value_id), assembler_->SmiConstant(0)), |
| 167 FromId(label_id), &pass); | 168 FromId(label_id), &pass); |
| 168 assembler_->Bind(&pass); | 169 assembler_->Bind(&pass); |
| 169 } | 170 } |
| 170 | 171 |
| 171 FastAccessorAssembler::ValueId FastAccessorAssembler::Call( | 172 FastAccessorAssembler::ValueId FastAccessorAssembler::Call( |
| 172 FunctionCallback callback_function, ValueId arg) { | 173 FunctionCallback callback_function, ValueId arg) { |
| 173 CHECK_EQ(kBuilding, state_); | 174 CHECK_EQ(kBuilding, state_); |
| 174 | 175 |
| 175 // Wrap the FunctionCallback in an ExternalReference. | 176 // Wrap the FunctionCallback in an ExternalReference. |
| 176 ApiFunction callback_api_function(FUNCTION_ADDR(callback_function)); | 177 ApiFunction callback_api_function(FUNCTION_ADDR(callback_function)); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 assembler_->CallStubN(descriptor, kJSParameterCount, target, args); | 210 assembler_->CallStubN(descriptor, kJSParameterCount, target, args); |
| 210 | 211 |
| 211 return FromRaw(call); | 212 return FromRaw(call); |
| 212 } | 213 } |
| 213 | 214 |
| 214 void FastAccessorAssembler::CheckIsJSObjectOrJump(ValueId value_id, | 215 void FastAccessorAssembler::CheckIsJSObjectOrJump(ValueId value_id, |
| 215 LabelId label_id) { | 216 LabelId label_id) { |
| 216 CHECK_EQ(kBuilding, state_); | 217 CHECK_EQ(kBuilding, state_); |
| 217 | 218 |
| 218 // Determine the 'value' object's instance type. | 219 // Determine the 'value' object's instance type. |
| 219 Node* object_map = assembler_->LoadObjectField( | 220 Node* instance_type = assembler_->LoadInstanceType(FromId(value_id)); |
| 220 FromId(value_id), Internals::kHeapObjectMapOffset, | |
| 221 MachineType::Pointer()); | |
| 222 | 221 |
| 223 Node* instance_type = assembler_->WordAnd( | 222 CodeAssemblerLabel is_jsobject(assembler_.get()); |
| 224 assembler_->LoadObjectField(object_map, | |
| 225 Internals::kMapInstanceTypeAndBitFieldOffset, | |
| 226 MachineType::Uint16()), | |
| 227 assembler_->IntPtrConstant(0xff)); | |
| 228 | |
| 229 CodeStubAssembler::Label is_jsobject(assembler_.get()); | |
| 230 | 223 |
| 231 // Check whether we have a proper JSObject. | 224 // Check whether we have a proper JSObject. |
| 232 assembler_->GotoIf( | 225 assembler_->GotoIf( |
| 233 assembler_->WordEqual( | 226 assembler_->Word32Equal( |
| 234 instance_type, assembler_->IntPtrConstant(Internals::kJSObjectType)), | 227 instance_type, assembler_->Int32Constant(Internals::kJSObjectType)), |
| 235 &is_jsobject); | 228 &is_jsobject); |
| 236 | 229 |
| 237 // JSApiObject?. | 230 // JSApiObject?. |
| 238 assembler_->GotoUnless( | 231 assembler_->GotoUnless( |
| 239 assembler_->WordEqual(instance_type, assembler_->IntPtrConstant( | 232 assembler_->Word32Equal(instance_type, assembler_->Int32Constant( |
| 240 Internals::kJSApiObjectType)), | 233 Internals::kJSApiObjectType)), |
| 241 FromId(label_id)); | 234 FromId(label_id)); |
| 242 | 235 |
| 243 // Continue. | 236 // Continue. |
| 244 assembler_->Goto(&is_jsobject); | 237 assembler_->Goto(&is_jsobject); |
| 245 assembler_->Bind(&is_jsobject); | 238 assembler_->Bind(&is_jsobject); |
| 246 } | 239 } |
| 247 | 240 |
| 248 MaybeHandle<Code> FastAccessorAssembler::Build() { | 241 MaybeHandle<Code> FastAccessorAssembler::Build() { |
| 249 CHECK_EQ(kBuilding, state_); | 242 CHECK_EQ(kBuilding, state_); |
| 250 Handle<Code> code = compiler::CodeAssembler::GenerateCode(&assembler_state_); | 243 Handle<Code> code = compiler::CodeAssembler::GenerateCode( |
| 244 assembler_state_.get(), FLAG_csa_verify); |
| 251 state_ = !code.is_null() ? kBuilt : kError; | 245 state_ = !code.is_null() ? kBuilt : kError; |
| 252 Clear(); | 246 Clear(); |
| 253 return code; | 247 return code; |
| 254 } | 248 } |
| 255 | 249 |
| 256 FastAccessorAssembler::ValueId FastAccessorAssembler::FromRaw(Node* node) { | 250 FastAccessorAssembler::ValueId FastAccessorAssembler::FromRaw(Node* node) { |
| 257 nodes_.push_back(node); | 251 nodes_.push_back(node); |
| 258 ValueId value = {nodes_.size() - 1}; | 252 ValueId value_id = {nodes_.size() - 1}; |
| 259 return value; | 253 return value_id; |
| 260 } | 254 } |
| 261 | 255 |
| 262 FastAccessorAssembler::LabelId FastAccessorAssembler::FromRaw( | 256 FastAccessorAssembler::LabelId FastAccessorAssembler::FromRaw( |
| 263 CodeStubAssembler::Label* label) { | 257 CodeAssemblerLabel* label) { |
| 264 labels_.push_back(label); | 258 labels_.push_back(label); |
| 265 LabelId label_id = {labels_.size() - 1}; | 259 LabelId label_id = {labels_.size() - 1}; |
| 266 return label_id; | 260 return label_id; |
| 267 } | 261 } |
| 268 | 262 |
| 269 Node* FastAccessorAssembler::FromId(ValueId value) const { | 263 Node* FastAccessorAssembler::FromId(ValueId value) const { |
| 270 CHECK_LT(value.value_id, nodes_.size()); | 264 CHECK_LT(value.value_id, nodes_.size()); |
| 271 CHECK_NOT_NULL(nodes_.at(value.value_id)); | 265 CHECK_NOT_NULL(nodes_.at(value.value_id)); |
| 272 return nodes_.at(value.value_id); | 266 return nodes_.at(value.value_id); |
| 273 } | 267 } |
| 274 | 268 |
| 275 CodeStubAssembler::Label* FastAccessorAssembler::FromId(LabelId label) const { | 269 CodeAssemblerLabel* FastAccessorAssembler::FromId(LabelId label) const { |
| 276 CHECK_LT(label.label_id, labels_.size()); | 270 CHECK_LT(label.label_id, labels_.size()); |
| 277 CHECK_NOT_NULL(labels_.at(label.label_id)); | 271 CHECK_NOT_NULL(labels_.at(label.label_id)); |
| 278 return labels_.at(label.label_id); | 272 return labels_.at(label.label_id); |
| 279 } | 273 } |
| 280 | 274 |
| 281 void FastAccessorAssembler::Clear() { | 275 void FastAccessorAssembler::Clear() { |
| 282 for (auto label : labels_) { | 276 for (auto label : labels_) { |
| 283 delete label; | 277 delete label; |
| 284 } | 278 } |
| 285 nodes_.clear(); | 279 nodes_.clear(); |
| 286 labels_.clear(); | 280 labels_.clear(); |
| 287 } | 281 } |
| 288 | 282 |
| 289 } // namespace internal | 283 } // namespace internal |
| 290 } // namespace v8 | 284 } // namespace v8 |
| OLD | NEW |