Home | History | Annotate | Download | only in src
      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, &not_null);
    143   assembler_->Bind(&is_null);
    144   assembler_->Return(assembler_->NullConstant());
    145   assembler_->Bind(&not_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