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 3 // found in the LICENSE file. 4 5 #include "src/fast-accessor-assembler.h" 6 7 #include "src/base/logging.h" 8 #include "src/code-stub-assembler.h" 9 #include "src/code-stubs.h" // For CallApiCallbackStub. 10 #include "src/handles-inl.h" 11 #include "src/objects-inl.h" 12 #include "src/objects.h" // For FAA::LoadInternalField impl. 13 14 namespace v8 { 15 namespace internal { 16 17 using compiler::Node; 18 using compiler::CodeAssemblerLabel; 19 using compiler::CodeAssemblerVariable; 20 21 FastAccessorAssembler::FastAccessorAssembler(Isolate* isolate) 22 : zone_(isolate->allocator(), ZONE_NAME), 23 isolate_(isolate), 24 assembler_state_(new compiler::CodeAssemblerState( 25 isolate, zone(), 1, Code::ComputeFlags(Code::STUB), 26 "FastAccessorAssembler")), 27 assembler_(new CodeStubAssembler(assembler_state_.get())), 28 state_(kBuilding) {} 29 30 FastAccessorAssembler::~FastAccessorAssembler() { Clear(); } 31 32 FastAccessorAssembler::ValueId FastAccessorAssembler::IntegerConstant( 33 int const_value) { 34 CHECK_EQ(kBuilding, state_); 35 return FromRaw(assembler_->NumberConstant(const_value)); 36 } 37 38 FastAccessorAssembler::ValueId FastAccessorAssembler::GetReceiver() { 39 CHECK_EQ(kBuilding, state_); 40 41 // For JS functions, the receiver is parameter 0. 42 return FromRaw(assembler_->Parameter(0)); 43 } 44 45 FastAccessorAssembler::ValueId FastAccessorAssembler::LoadInternalField( 46 ValueId value_id, int field_no) { 47 CHECK_EQ(kBuilding, state_); 48 49 CodeAssemblerVariable result(assembler_.get(), 50 MachineRepresentation::kTagged); 51 LabelId is_not_jsobject = MakeLabel(); 52 CodeAssemblerLabel merge(assembler_.get(), &result); 53 54 CheckIsJSObjectOrJump(value_id, is_not_jsobject); 55 56 Node* internal_field = assembler_->LoadObjectField( 57 FromId(value_id), JSObject::kHeaderSize + kPointerSize * field_no); 58 59 result.Bind(internal_field); 60 assembler_->Goto(&merge); 61 62 // Return null, mimicking the C++ counterpart. 63 SetLabel(is_not_jsobject); 64 result.Bind(assembler_->NullConstant()); 65 assembler_->Goto(&merge); 66 67 // Return. 68 assembler_->Bind(&merge); 69 return FromRaw(result.value()); 70 } 71 72 FastAccessorAssembler::ValueId 73 FastAccessorAssembler::LoadInternalFieldUnchecked(ValueId value_id, 74 int field_no) { 75 CHECK_EQ(kBuilding, state_); 76 77 // Defensive debug checks. 78 if (FLAG_debug_code) { 79 LabelId is_jsobject = MakeLabel(); 80 LabelId is_not_jsobject = MakeLabel(); 81 CheckIsJSObjectOrJump(value_id, is_not_jsobject); 82 assembler_->Goto(FromId(is_jsobject)); 83 84 SetLabel(is_not_jsobject); 85 assembler_->DebugBreak(); 86 assembler_->Goto(FromId(is_jsobject)); 87 88 SetLabel(is_jsobject); 89 } 90 91 Node* result = assembler_->LoadObjectField( 92 FromId(value_id), JSObject::kHeaderSize + kPointerSize * field_no); 93 94 return FromRaw(result); 95 } 96 97 FastAccessorAssembler::ValueId FastAccessorAssembler::LoadValue( 98 ValueId value_id, int offset) { 99 CHECK_EQ(kBuilding, state_); 100 return FromRaw(assembler_->LoadBufferObject(FromId(value_id), offset, 101 MachineType::IntPtr())); 102 } 103 104 FastAccessorAssembler::ValueId FastAccessorAssembler::LoadObject( 105 ValueId value_id, int offset) { 106 CHECK_EQ(kBuilding, state_); 107 return FromRaw(assembler_->LoadBufferObject( 108 assembler_->LoadBufferObject(FromId(value_id), offset), 0, 109 MachineType::AnyTagged())); 110 } 111 112 FastAccessorAssembler::ValueId FastAccessorAssembler::ToSmi(ValueId value_id) { 113 CHECK_EQ(kBuilding, state_); 114 return FromRaw(assembler_->SmiTag(FromId(value_id))); 115 } 116 117 void FastAccessorAssembler::ReturnValue(ValueId value_id) { 118 CHECK_EQ(kBuilding, state_); 119 assembler_->Return(FromId(value_id)); 120 } 121 122 void FastAccessorAssembler::CheckFlagSetOrReturnNull(ValueId value_id, 123 int mask) { 124 CHECK_EQ(kBuilding, state_); 125 CodeAssemblerLabel pass(assembler_.get()); 126 CodeAssemblerLabel fail(assembler_.get()); 127 Node* value = FromId(value_id); 128 assembler_->Branch( 129 assembler_->IsSetWord(assembler_->BitcastTaggedToWord(value), mask), 130 &pass, &fail); 131 assembler_->Bind(&fail); 132 assembler_->Return(assembler_->NullConstant()); 133 assembler_->Bind(&pass); 134 } 135 136 void FastAccessorAssembler::CheckNotZeroOrReturnNull(ValueId value_id) { 137 CHECK_EQ(kBuilding, state_); 138 CodeAssemblerLabel is_null(assembler_.get()); 139 CodeAssemblerLabel not_null(assembler_.get()); 140 assembler_->Branch( 141 assembler_->WordEqual(FromId(value_id), assembler_->SmiConstant(0)), 142 &is_null, ¬_null); 143 assembler_->Bind(&is_null); 144 assembler_->Return(assembler_->NullConstant()); 145 assembler_->Bind(¬_null); 146 } 147 148 FastAccessorAssembler::LabelId FastAccessorAssembler::MakeLabel() { 149 CHECK_EQ(kBuilding, state_); 150 return FromRaw(new CodeAssemblerLabel(assembler_.get())); 151 } 152 153 void FastAccessorAssembler::SetLabel(LabelId label_id) { 154 CHECK_EQ(kBuilding, state_); 155 assembler_->Bind(FromId(label_id)); 156 } 157 158 void FastAccessorAssembler::Goto(LabelId label_id) { 159 CHECK_EQ(kBuilding, state_); 160 assembler_->Goto(FromId(label_id)); 161 } 162 163 void FastAccessorAssembler::CheckNotZeroOrJump(ValueId value_id, 164 LabelId label_id) { 165 CHECK_EQ(kBuilding, state_); 166 CodeAssemblerLabel pass(assembler_.get()); 167 assembler_->Branch( 168 assembler_->WordEqual(FromId(value_id), assembler_->SmiConstant(0)), 169 FromId(label_id), &pass); 170 assembler_->Bind(&pass); 171 } 172 173 FastAccessorAssembler::ValueId FastAccessorAssembler::Call( 174 FunctionCallback callback_function, ValueId arg) { 175 CHECK_EQ(kBuilding, state_); 176 177 // Wrap the FunctionCallback in an ExternalReference. 178 ApiFunction callback_api_function(FUNCTION_ADDR(callback_function)); 179 ExternalReference callback(&callback_api_function, 180 ExternalReference::DIRECT_API_CALL, isolate()); 181 182 // Create & call API callback via stub. 183 const int kJSParameterCount = 1; 184 CallApiCallbackStub stub(isolate(), kJSParameterCount, true, true); 185 CallInterfaceDescriptor descriptor = stub.GetCallInterfaceDescriptor(); 186 DCHECK_EQ(4, descriptor.GetParameterCount()); 187 DCHECK_EQ(0, descriptor.GetStackParameterCount()); 188 Node* context = assembler_->GetJSContextParameter(); 189 Node* target = assembler_->HeapConstant(stub.GetCode()); 190 191 Node* call = assembler_->CallStub( 192 descriptor, target, context, 193 assembler_->UndefinedConstant(), // callee (there's no JSFunction) 194 assembler_->UndefinedConstant(), // call_data (undefined) 195 assembler_->Parameter(0), // receiver (same as holder in this case) 196 assembler_->ExternalConstant(callback), // API callback function 197 FromId(arg)); // JS argument, on stack 198 return FromRaw(call); 199 } 200 201 void FastAccessorAssembler::CheckIsJSObjectOrJump(ValueId value_id, 202 LabelId label_id) { 203 CHECK_EQ(kBuilding, state_); 204 205 // Determine the 'value' object's instance type. 206 Node* instance_type = assembler_->LoadInstanceType(FromId(value_id)); 207 208 CodeAssemblerLabel is_jsobject(assembler_.get()); 209 210 // Check whether we have a proper JSObject. 211 assembler_->GotoIf( 212 assembler_->Word32Equal( 213 instance_type, assembler_->Int32Constant(Internals::kJSObjectType)), 214 &is_jsobject); 215 216 // JSApiObject?. 217 assembler_->GotoIfNot( 218 assembler_->Word32Equal(instance_type, assembler_->Int32Constant( 219 Internals::kJSApiObjectType)), 220 FromId(label_id)); 221 222 // Continue. 223 assembler_->Goto(&is_jsobject); 224 assembler_->Bind(&is_jsobject); 225 } 226 227 MaybeHandle<Code> FastAccessorAssembler::Build() { 228 CHECK_EQ(kBuilding, state_); 229 Handle<Code> code = 230 compiler::CodeAssembler::GenerateCode(assembler_state_.get()); 231 state_ = !code.is_null() ? kBuilt : kError; 232 Clear(); 233 return code; 234 } 235 236 FastAccessorAssembler::ValueId FastAccessorAssembler::FromRaw(Node* node) { 237 nodes_.push_back(node); 238 ValueId value_id = {nodes_.size() - 1}; 239 return value_id; 240 } 241 242 FastAccessorAssembler::LabelId FastAccessorAssembler::FromRaw( 243 CodeAssemblerLabel* label) { 244 labels_.push_back(label); 245 LabelId label_id = {labels_.size() - 1}; 246 return label_id; 247 } 248 249 Node* FastAccessorAssembler::FromId(ValueId value) const { 250 CHECK_LT(value.value_id, nodes_.size()); 251 CHECK_NOT_NULL(nodes_.at(value.value_id)); 252 return nodes_.at(value.value_id); 253 } 254 255 CodeAssemblerLabel* FastAccessorAssembler::FromId(LabelId label) const { 256 CHECK_LT(label.label_id, labels_.size()); 257 CHECK_NOT_NULL(labels_.at(label.label_id)); 258 return labels_.at(label.label_id); 259 } 260 261 void FastAccessorAssembler::Clear() { 262 for (auto label : labels_) { 263 delete label; 264 } 265 nodes_.clear(); 266 labels_.clear(); 267 } 268 269 } // namespace internal 270 } // namespace v8 271