fast-accessor-assembler.cc 8.65 KB
Newer Older
1 2 3 4
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "src/fast-accessor-assembler.h"
6 7

#include "src/base/logging.h"
8
#include "src/code-stub-assembler.h"
vogelheim's avatar
vogelheim committed
9
#include "src/code-stubs.h"  // For CallApiCallbackStub.
10
#include "src/handles-inl.h"
11 12
#include "src/objects.h"  // For FAA::LoadInternalField impl.

13 14 15
namespace v8 {
namespace internal {

16 17 18 19
using compiler::Node;
using compiler::CodeAssemblerLabel;
using compiler::CodeAssemblerVariable;

20
FastAccessorAssembler::FastAccessorAssembler(Isolate* isolate)
21
    : zone_(isolate->allocator(), ZONE_NAME),
22
      isolate_(isolate),
23 24 25 26
      assembler_state_(new compiler::CodeAssemblerState(
          isolate, zone(), 1, Code::ComputeFlags(Code::STUB),
          "FastAccessorAssembler")),
      assembler_(new CodeStubAssembler(assembler_state_.get())),
27 28
      state_(kBuilding) {}

29
FastAccessorAssembler::~FastAccessorAssembler() { Clear(); }
30 31 32 33 34 35 36 37 38 39

FastAccessorAssembler::ValueId FastAccessorAssembler::IntegerConstant(
    int const_value) {
  CHECK_EQ(kBuilding, state_);
  return FromRaw(assembler_->NumberConstant(const_value));
}

FastAccessorAssembler::ValueId FastAccessorAssembler::GetReceiver() {
  CHECK_EQ(kBuilding, state_);

40
  // For JS functions, the receiver is parameter 0.
41 42 43 44
  return FromRaw(assembler_->Parameter(0));
}

FastAccessorAssembler::ValueId FastAccessorAssembler::LoadInternalField(
45
    ValueId value_id, int field_no) {
46
  CHECK_EQ(kBuilding, state_);
47

48 49
  CodeAssemblerVariable result(assembler_.get(),
                               MachineRepresentation::kTagged);
50
  LabelId is_not_jsobject = MakeLabel();
51
  CodeAssemblerLabel merge(assembler_.get(), &result);
52

53
  CheckIsJSObjectOrJump(value_id, is_not_jsobject);
54

55
  Node* internal_field = assembler_->LoadObjectField(
56
      FromId(value_id), JSObject::kHeaderSize + kPointerSize * field_no);
57

58
  result.Bind(internal_field);
59 60
  assembler_->Goto(&merge);

61 62 63
  // Return null, mimicking the C++ counterpart.
  SetLabel(is_not_jsobject);
  result.Bind(assembler_->NullConstant());
64 65 66 67
  assembler_->Goto(&merge);

  // Return.
  assembler_->Bind(&merge);
68
  return FromRaw(result.value());
69 70
}

71
FastAccessorAssembler::ValueId
72 73
FastAccessorAssembler::LoadInternalFieldUnchecked(ValueId value_id,
                                                  int field_no) {
74 75 76 77 78 79
  CHECK_EQ(kBuilding, state_);

  // Defensive debug checks.
  if (FLAG_debug_code) {
    LabelId is_jsobject = MakeLabel();
    LabelId is_not_jsobject = MakeLabel();
80
    CheckIsJSObjectOrJump(value_id, is_not_jsobject);
81 82 83 84 85 86 87 88 89 90
    assembler_->Goto(FromId(is_jsobject));

    SetLabel(is_not_jsobject);
    assembler_->DebugBreak();
    assembler_->Goto(FromId(is_jsobject));

    SetLabel(is_jsobject);
  }

  Node* result = assembler_->LoadObjectField(
91
      FromId(value_id), JSObject::kHeaderSize + kPointerSize * field_no);
92 93 94 95

  return FromRaw(result);
}

96 97
FastAccessorAssembler::ValueId FastAccessorAssembler::LoadValue(
    ValueId value_id, int offset) {
98
  CHECK_EQ(kBuilding, state_);
99
  return FromRaw(assembler_->LoadBufferObject(FromId(value_id), offset,
100
                                              MachineType::IntPtr()));
101 102
}

103 104
FastAccessorAssembler::ValueId FastAccessorAssembler::LoadObject(
    ValueId value_id, int offset) {
105
  CHECK_EQ(kBuilding, state_);
106
  return FromRaw(assembler_->LoadBufferObject(
107 108
      assembler_->LoadBufferObject(FromId(value_id), offset), 0,
      MachineType::AnyTagged()));
109 110
}

111
FastAccessorAssembler::ValueId FastAccessorAssembler::ToSmi(ValueId value_id) {
112
  CHECK_EQ(kBuilding, state_);
113
  return FromRaw(assembler_->SmiTag(FromId(value_id)));
114 115
}

116
void FastAccessorAssembler::ReturnValue(ValueId value_id) {
117
  CHECK_EQ(kBuilding, state_);
118
  assembler_->Return(FromId(value_id));
119 120
}

121 122
void FastAccessorAssembler::CheckFlagSetOrReturnNull(ValueId value_id,
                                                     int mask) {
123
  CHECK_EQ(kBuilding, state_);
124 125 126
  CodeAssemblerLabel pass(assembler_.get());
  CodeAssemblerLabel fail(assembler_.get());
  Node* value = FromId(value_id);
127
  assembler_->Branch(
128 129
      assembler_->IsSetWord(assembler_->BitcastTaggedToWord(value), mask),
      &pass, &fail);
130 131 132 133 134
  assembler_->Bind(&fail);
  assembler_->Return(assembler_->NullConstant());
  assembler_->Bind(&pass);
}

135
void FastAccessorAssembler::CheckNotZeroOrReturnNull(ValueId value_id) {
136
  CHECK_EQ(kBuilding, state_);
137 138
  CodeAssemblerLabel is_null(assembler_.get());
  CodeAssemblerLabel not_null(assembler_.get());
139
  assembler_->Branch(
140
      assembler_->WordEqual(FromId(value_id), assembler_->SmiConstant(0)),
141 142 143 144 145 146 147 148
      &is_null, &not_null);
  assembler_->Bind(&is_null);
  assembler_->Return(assembler_->NullConstant());
  assembler_->Bind(&not_null);
}

FastAccessorAssembler::LabelId FastAccessorAssembler::MakeLabel() {
  CHECK_EQ(kBuilding, state_);
149
  return FromRaw(new CodeAssemblerLabel(assembler_.get()));
150 151 152 153 154 155 156
}

void FastAccessorAssembler::SetLabel(LabelId label_id) {
  CHECK_EQ(kBuilding, state_);
  assembler_->Bind(FromId(label_id));
}

157 158 159 160 161
void FastAccessorAssembler::Goto(LabelId label_id) {
  CHECK_EQ(kBuilding, state_);
  assembler_->Goto(FromId(label_id));
}

162 163 164
void FastAccessorAssembler::CheckNotZeroOrJump(ValueId value_id,
                                               LabelId label_id) {
  CHECK_EQ(kBuilding, state_);
165
  CodeAssemblerLabel pass(assembler_.get());
166
  assembler_->Branch(
167
      assembler_->WordEqual(FromId(value_id), assembler_->SmiConstant(0)),
168
      FromId(label_id), &pass);
169 170 171
  assembler_->Bind(&pass);
}

172 173 174 175 176 177 178
FastAccessorAssembler::ValueId FastAccessorAssembler::Call(
    FunctionCallback callback_function, ValueId arg) {
  CHECK_EQ(kBuilding, state_);

  // Wrap the FunctionCallback in an ExternalReference.
  ApiFunction callback_api_function(FUNCTION_ADDR(callback_function));
  ExternalReference callback(&callback_api_function,
179 180 181
                             ExternalReference::DIRECT_API_CALL, isolate());

  // Create & call API callback via stub.
182 183 184 185 186
  const int kJSParameterCount = 1;
  CallApiCallbackStub stub(isolate(), kJSParameterCount, true, true);
  CallInterfaceDescriptor descriptor = stub.GetCallInterfaceDescriptor();
  DCHECK_EQ(4, descriptor.GetParameterCount());
  DCHECK_EQ(0, descriptor.GetStackParameterCount());
187
  Node* context = assembler_->GetJSContextParameter();
188 189
  Node* target = assembler_->HeapConstant(stub.GetCode());

190 191 192 193 194 195 196
  Node* call = assembler_->CallStub(
      descriptor, target, context,
      assembler_->UndefinedConstant(),  // callee (there's no JSFunction)
      assembler_->UndefinedConstant(),  // call_data (undefined)
      assembler_->Parameter(0),  // receiver (same as holder in this case)
      assembler_->ExternalConstant(callback),  // API callback function
      FromId(arg));                            // JS argument, on stack
197 198 199
  return FromRaw(call);
}

200 201 202 203 204
void FastAccessorAssembler::CheckIsJSObjectOrJump(ValueId value_id,
                                                  LabelId label_id) {
  CHECK_EQ(kBuilding, state_);

  // Determine the 'value' object's instance type.
205
  Node* instance_type = assembler_->LoadInstanceType(FromId(value_id));
206

207
  CodeAssemblerLabel is_jsobject(assembler_.get());
208 209 210

  // Check whether we have a proper JSObject.
  assembler_->GotoIf(
211 212
      assembler_->Word32Equal(
          instance_type, assembler_->Int32Constant(Internals::kJSObjectType)),
213 214 215 216
      &is_jsobject);

  // JSApiObject?.
  assembler_->GotoUnless(
217 218
      assembler_->Word32Equal(instance_type, assembler_->Int32Constant(
                                                 Internals::kJSApiObjectType)),
219 220 221 222 223 224 225
      FromId(label_id));

  // Continue.
  assembler_->Goto(&is_jsobject);
  assembler_->Bind(&is_jsobject);
}

226 227
MaybeHandle<Code> FastAccessorAssembler::Build() {
  CHECK_EQ(kBuilding, state_);
228 229
  Handle<Code> code =
      compiler::CodeAssembler::GenerateCode(assembler_state_.get());
230
  state_ = !code.is_null() ? kBuilt : kError;
231
  Clear();
232 233 234 235 236
  return code;
}

FastAccessorAssembler::ValueId FastAccessorAssembler::FromRaw(Node* node) {
  nodes_.push_back(node);
237 238
  ValueId value_id = {nodes_.size() - 1};
  return value_id;
239 240 241
}

FastAccessorAssembler::LabelId FastAccessorAssembler::FromRaw(
242
    CodeAssemblerLabel* label) {
243 244 245 246 247 248 249 250 251 252 253
  labels_.push_back(label);
  LabelId label_id = {labels_.size() - 1};
  return label_id;
}

Node* FastAccessorAssembler::FromId(ValueId value) const {
  CHECK_LT(value.value_id, nodes_.size());
  CHECK_NOT_NULL(nodes_.at(value.value_id));
  return nodes_.at(value.value_id);
}

254
CodeAssemblerLabel* FastAccessorAssembler::FromId(LabelId label) const {
255 256 257 258 259
  CHECK_LT(label.label_id, labels_.size());
  CHECK_NOT_NULL(labels_.at(label.label_id));
  return labels_.at(label.label_id);
}

260 261 262 263 264 265 266
void FastAccessorAssembler::Clear() {
  for (auto label : labels_) {
    delete label;
  }
  nodes_.clear();
  labels_.clear();
}
267 268 269

}  // namespace internal
}  // namespace v8