api-arguments-inl.h 16.6 KB
Newer Older
1 2 3 4
// Copyright 2016 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 6 7
#ifndef V8_API_ARGUMENTS_INL_H_
#define V8_API_ARGUMENTS_INL_H_

8 9
#include "src/api-arguments.h"

10
#include "src/api-inl.h"
11
#include "src/debug/debug.h"
12
#include "src/objects/api-callbacks.h"
13
#include "src/objects/slots-inl.h"
14 15 16 17 18 19
#include "src/tracing/trace-event.h"
#include "src/vm-state-inl.h"

namespace v8 {
namespace internal {

20 21 22 23 24 25 26 27 28 29 30
void Object::VerifyApiCallResultType() {
#if DEBUG
  if (IsSmi()) return;
  DCHECK(IsHeapObject());
  if (!(IsString() || IsSymbol() || IsJSReceiver() || IsHeapNumber() ||
        IsBigInt() || IsUndefined() || IsTrue() || IsFalse() || IsNull())) {
    FATAL("API call returned invalid object");
  }
#endif  // DEBUG
}

31 32 33
CustomArgumentsBase::CustomArgumentsBase(Isolate* isolate)
    : Relocatable(isolate) {}

34 35
template <typename T>
CustomArguments<T>::~CustomArguments() {
36
  slot_at(kReturnValueOffset).store(Object(kHandleZapValue));
37 38
}

39 40 41 42
template <typename T>
template <typename V>
Handle<V> CustomArguments<T>::GetReturnValue(Isolate* isolate) {
  // Check the ReturnValue.
43
  FullObjectSlot slot = slot_at(kReturnValueOffset);
44
  // Nothing was set, return empty handle as per previous behaviour.
45 46
  if ((*slot)->IsTheHole(isolate)) return Handle<V>();
  Handle<V> result = Handle<V>::cast(Handle<Object>(slot.location()));
47 48 49 50
  result->VerifyApiCallResultType();
  return result;
}

51
inline JSObject PropertyCallbackArguments::holder() {
52
  return JSObject::cast(*slot_at(T::kHolderIndex));
53 54
}

55 56
inline Object PropertyCallbackArguments::receiver() {
  return *slot_at(T::kThisIndex);
57 58
}

59
inline JSObject FunctionCallbackArguments::holder() {
60
  return JSObject::cast(*slot_at(T::kHolderIndex));
61 62
}

63 64 65
#define FOR_EACH_CALLBACK(F)                        \
  F(Query, query, Object, v8::Integer, interceptor) \
  F(Deleter, deleter, Object, v8::Boolean, Handle<Object>())
66

67 68 69 70 71
#define DCHECK_NAME_COMPATIBLE(interceptor, name) \
  DCHECK(interceptor->is_named());                \
  DCHECK(!name->IsPrivate());                     \
  DCHECK_IMPLIES(name->IsSymbol(), interceptor->can_intercept_symbols());

72 73 74 75 76 77 78 79 80
#define PREPARE_CALLBACK_INFO(ISOLATE, F, RETURN_VALUE, API_RETURN_TYPE, \
                              CALLBACK_INFO, RECEIVER, ACCESSOR_KIND)    \
  if (ISOLATE->debug_execution_mode() == DebugInfo::kSideEffects &&      \
      !ISOLATE->debug()->PerformSideEffectCheckForCallback(              \
          CALLBACK_INFO, RECEIVER, Debug::k##ACCESSOR_KIND)) {           \
    return RETURN_VALUE();                                               \
  }                                                                      \
  VMState<EXTERNAL> state(ISOLATE);                                      \
  ExternalCallbackScope call_scope(ISOLATE, FUNCTION_ADDR(F));           \
81
  PropertyCallbackInfo<API_RETURN_TYPE> callback_info(values_);
82 83 84 85 86 87 88 89

#define PREPARE_CALLBACK_INFO_FAIL_SIDE_EFFECT_CHECK(ISOLATE, F, RETURN_VALUE, \
                                                     API_RETURN_TYPE)          \
  if (ISOLATE->debug_execution_mode() == DebugInfo::kSideEffects) {            \
    return RETURN_VALUE();                                                     \
  }                                                                            \
  VMState<EXTERNAL> state(ISOLATE);                                            \
  ExternalCallbackScope call_scope(ISOLATE, FUNCTION_ADDR(F));                 \
90
  PropertyCallbackInfo<API_RETURN_TYPE> callback_info(values_);
91

92 93 94
#define CREATE_NAMED_CALLBACK(FUNCTION, TYPE, RETURN_TYPE, API_RETURN_TYPE,   \
                              INFO_FOR_SIDE_EFFECT)                           \
  Handle<RETURN_TYPE> PropertyCallbackArguments::CallNamed##FUNCTION(         \
95
      Handle<InterceptorInfo> interceptor, Handle<Name> name) {               \
96
    DCHECK_NAME_COMPATIBLE(interceptor, name);                                \
97
    Isolate* isolate = this->isolate();                                       \
98
    RuntimeCallTimerScope timer(                                              \
99
        isolate, RuntimeCallCounterId::kNamed##FUNCTION##Callback);           \
100
    Handle<Object> receiver_check_unsupported;                                \
101 102 103 104
    GenericNamedProperty##FUNCTION##Callback f =                              \
        ToCData<GenericNamedProperty##FUNCTION##Callback>(                    \
            interceptor->TYPE());                                             \
    PREPARE_CALLBACK_INFO(isolate, f, Handle<RETURN_TYPE>, API_RETURN_TYPE,   \
105 106
                          INFO_FOR_SIDE_EFFECT, receiver_check_unsupported,   \
                          NotAccessor);                                       \
107
    LOG(isolate,                                                              \
108
        ApiNamedPropertyAccess("interceptor-named-" #TYPE, holder(), *name)); \
109
    f(v8::Utils::ToLocal(name), callback_info);                               \
110
    return GetReturnValue<RETURN_TYPE>(isolate);                              \
111 112
  }

113 114 115
FOR_EACH_CALLBACK(CREATE_NAMED_CALLBACK)
#undef CREATE_NAMED_CALLBACK

116 117 118 119 120 121 122 123
#define CREATE_INDEXED_CALLBACK(FUNCTION, TYPE, RETURN_TYPE, API_RETURN_TYPE, \
                                INFO_FOR_SIDE_EFFECT)                         \
  Handle<RETURN_TYPE> PropertyCallbackArguments::CallIndexed##FUNCTION(       \
      Handle<InterceptorInfo> interceptor, uint32_t index) {                  \
    DCHECK(!interceptor->is_named());                                         \
    Isolate* isolate = this->isolate();                                       \
    RuntimeCallTimerScope timer(                                              \
        isolate, RuntimeCallCounterId::kIndexed##FUNCTION##Callback);         \
124
    Handle<Object> receiver_check_unsupported;                                \
125 126 127
    IndexedProperty##FUNCTION##Callback f =                                   \
        ToCData<IndexedProperty##FUNCTION##Callback>(interceptor->TYPE());    \
    PREPARE_CALLBACK_INFO(isolate, f, Handle<RETURN_TYPE>, API_RETURN_TYPE,   \
128 129
                          INFO_FOR_SIDE_EFFECT, receiver_check_unsupported,   \
                          NotAccessor);                                       \
130 131 132 133
    LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-" #TYPE,       \
                                          holder(), index));                  \
    f(index, callback_info);                                                  \
    return GetReturnValue<RETURN_TYPE>(isolate);                              \
134 135
  }

136
FOR_EACH_CALLBACK(CREATE_INDEXED_CALLBACK)
137

138 139 140
#undef FOR_EACH_CALLBACK
#undef CREATE_INDEXED_CALLBACK

141
Handle<Object> FunctionCallbackArguments::Call(CallHandlerInfo handler) {
142 143 144 145 146
  Isolate* isolate = this->isolate();
  LOG(isolate, ApiObjectAccess("call", holder()));
  RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kFunctionCallback);
  v8::FunctionCallback f =
      v8::ToCData<v8::FunctionCallback>(handler->callback());
147
  Handle<Object> receiver_check_unsupported;
148
  if (isolate->debug_execution_mode() == DebugInfo::kSideEffects &&
149
      !isolate->debug()->PerformSideEffectCheckForCallback(
150 151
          handle(handler, isolate), receiver_check_unsupported,
          Debug::kNotAccessor)) {
152 153 154 155
    return Handle<Object>();
  }
  VMState<EXTERNAL> state(isolate);
  ExternalCallbackScope call_scope(isolate, FUNCTION_ADDR(f));
156
  FunctionCallbackInfo<v8::Value> info(values_, argv_, argc_);
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
  f(info);
  return GetReturnValue<Object>(isolate);
}

Handle<JSObject> PropertyCallbackArguments::CallNamedEnumerator(
    Handle<InterceptorInfo> interceptor) {
  DCHECK(interceptor->is_named());
  LOG(isolate(), ApiObjectAccess("interceptor-named-enumerator", holder()));
  RuntimeCallTimerScope timer(isolate(),
                              RuntimeCallCounterId::kNamedEnumeratorCallback);
  return CallPropertyEnumerator(interceptor);
}

Handle<JSObject> PropertyCallbackArguments::CallIndexedEnumerator(
    Handle<InterceptorInfo> interceptor) {
  DCHECK(!interceptor->is_named());
  LOG(isolate(), ApiObjectAccess("interceptor-indexed-enumerator", holder()));
  RuntimeCallTimerScope timer(isolate(),
                              RuntimeCallCounterId::kIndexedEnumeratorCallback);
  return CallPropertyEnumerator(interceptor);
}

179 180
Handle<Object> PropertyCallbackArguments::CallNamedGetter(
    Handle<InterceptorInfo> interceptor, Handle<Name> name) {
181
  DCHECK_NAME_COMPATIBLE(interceptor, name);
182 183 184 185 186 187 188
  Isolate* isolate = this->isolate();
  RuntimeCallTimerScope timer(isolate,
                              RuntimeCallCounterId::kNamedGetterCallback);
  LOG(isolate,
      ApiNamedPropertyAccess("interceptor-named-getter", holder(), *name));
  GenericNamedPropertyGetterCallback f =
      ToCData<GenericNamedPropertyGetterCallback>(interceptor->getter());
189
  return BasicCallNamedGetterCallback(f, name, interceptor);
190
}
191

192 193
Handle<Object> PropertyCallbackArguments::CallNamedDescriptor(
    Handle<InterceptorInfo> interceptor, Handle<Name> name) {
194
  DCHECK_NAME_COMPATIBLE(interceptor, name);
195 196 197 198 199 200 201 202
  Isolate* isolate = this->isolate();
  RuntimeCallTimerScope timer(isolate,
                              RuntimeCallCounterId::kNamedDescriptorCallback);
  LOG(isolate,
      ApiNamedPropertyAccess("interceptor-named-descriptor", holder(), *name));
  GenericNamedPropertyDescriptorCallback f =
      ToCData<GenericNamedPropertyDescriptorCallback>(
          interceptor->descriptor());
203
  return BasicCallNamedGetterCallback(f, name, interceptor);
204 205 206
}

Handle<Object> PropertyCallbackArguments::BasicCallNamedGetterCallback(
207
    GenericNamedPropertyGetterCallback f, Handle<Name> name,
208
    Handle<Object> info, Handle<Object> receiver) {
209 210
  DCHECK(!name->IsPrivate());
  Isolate* isolate = this->isolate();
211 212
  PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value, info, receiver,
                        Getter);
213 214 215 216 217 218 219
  f(v8::Utils::ToLocal(name), callback_info);
  return GetReturnValue<Object>(isolate);
}

Handle<Object> PropertyCallbackArguments::CallNamedSetter(
    Handle<InterceptorInfo> interceptor, Handle<Name> name,
    Handle<Object> value) {
220
  DCHECK_NAME_COMPATIBLE(interceptor, name);
221 222
  GenericNamedPropertySetterCallback f =
      ToCData<GenericNamedPropertySetterCallback>(interceptor->setter());
223
  Isolate* isolate = this->isolate();
224 225
  RuntimeCallTimerScope timer(isolate,
                              RuntimeCallCounterId::kNamedSetterCallback);
226 227
  PREPARE_CALLBACK_INFO_FAIL_SIDE_EFFECT_CHECK(isolate, f, Handle<Object>,
                                               v8::Value);
228 229
  LOG(isolate,
      ApiNamedPropertyAccess("interceptor-named-set", holder(), *name));
230
  f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), callback_info);
231 232 233
  return GetReturnValue<Object>(isolate);
}

234 235
Handle<Object> PropertyCallbackArguments::CallNamedDefiner(
    Handle<InterceptorInfo> interceptor, Handle<Name> name,
236
    const v8::PropertyDescriptor& desc) {
237
  DCHECK_NAME_COMPATIBLE(interceptor, name);
238
  Isolate* isolate = this->isolate();
239 240 241 242
  RuntimeCallTimerScope timer(isolate,
                              RuntimeCallCounterId::kNamedDefinerCallback);
  GenericNamedPropertyDefinerCallback f =
      ToCData<GenericNamedPropertyDefinerCallback>(interceptor->definer());
243 244
  PREPARE_CALLBACK_INFO_FAIL_SIDE_EFFECT_CHECK(isolate, f, Handle<Object>,
                                               v8::Value);
245 246
  LOG(isolate,
      ApiNamedPropertyAccess("interceptor-named-define", holder(), *name));
247
  f(v8::Utils::ToLocal(name), desc, callback_info);
248 249 250
  return GetReturnValue<Object>(isolate);
}

251 252 253
Handle<Object> PropertyCallbackArguments::CallIndexedSetter(
    Handle<InterceptorInfo> interceptor, uint32_t index, Handle<Object> value) {
  DCHECK(!interceptor->is_named());
254
  Isolate* isolate = this->isolate();
255 256 257 258
  RuntimeCallTimerScope timer(isolate,
                              RuntimeCallCounterId::kIndexedSetterCallback);
  IndexedPropertySetterCallback f =
      ToCData<IndexedPropertySetterCallback>(interceptor->setter());
259 260
  PREPARE_CALLBACK_INFO_FAIL_SIDE_EFFECT_CHECK(isolate, f, Handle<Object>,
                                               v8::Value);
261 262
  LOG(isolate,
      ApiIndexedPropertyAccess("interceptor-indexed-set", holder(), index));
263
  f(index, v8::Utils::ToLocal(value), callback_info);
264 265 266
  return GetReturnValue<Object>(isolate);
}

267 268
Handle<Object> PropertyCallbackArguments::CallIndexedDefiner(
    Handle<InterceptorInfo> interceptor, uint32_t index,
269
    const v8::PropertyDescriptor& desc) {
270
  DCHECK(!interceptor->is_named());
271
  Isolate* isolate = this->isolate();
272 273 274 275
  RuntimeCallTimerScope timer(isolate,
                              RuntimeCallCounterId::kIndexedDefinerCallback);
  IndexedPropertyDefinerCallback f =
      ToCData<IndexedPropertyDefinerCallback>(interceptor->definer());
276 277
  PREPARE_CALLBACK_INFO_FAIL_SIDE_EFFECT_CHECK(isolate, f, Handle<Object>,
                                               v8::Value);
278 279
  LOG(isolate,
      ApiIndexedPropertyAccess("interceptor-indexed-define", holder(), index));
280
  f(index, desc, callback_info);
281 282 283
  return GetReturnValue<Object>(isolate);
}

284 285 286
Handle<Object> PropertyCallbackArguments::CallIndexedGetter(
    Handle<InterceptorInfo> interceptor, uint32_t index) {
  DCHECK(!interceptor->is_named());
287
  Isolate* isolate = this->isolate();
288 289
  RuntimeCallTimerScope timer(isolate,
                              RuntimeCallCounterId::kNamedGetterCallback);
290
  LOG(isolate,
291 292 293
      ApiIndexedPropertyAccess("interceptor-indexed-getter", holder(), index));
  IndexedPropertyGetterCallback f =
      ToCData<IndexedPropertyGetterCallback>(interceptor->getter());
294
  return BasicCallIndexedGetterCallback(f, index, interceptor);
295 296 297 298 299 300 301 302 303 304 305 306
}

Handle<Object> PropertyCallbackArguments::CallIndexedDescriptor(
    Handle<InterceptorInfo> interceptor, uint32_t index) {
  DCHECK(!interceptor->is_named());
  Isolate* isolate = this->isolate();
  RuntimeCallTimerScope timer(isolate,
                              RuntimeCallCounterId::kIndexedDescriptorCallback);
  LOG(isolate, ApiIndexedPropertyAccess("interceptor-indexed-descriptor",
                                        holder(), index));
  IndexedPropertyDescriptorCallback f =
      ToCData<IndexedPropertyDescriptorCallback>(interceptor->descriptor());
307
  return BasicCallIndexedGetterCallback(f, index, interceptor);
308 309 310
}

Handle<Object> PropertyCallbackArguments::BasicCallIndexedGetterCallback(
311
    IndexedPropertyGetterCallback f, uint32_t index, Handle<Object> info) {
312
  Isolate* isolate = this->isolate();
313 314 315
  Handle<Object> receiver_check_unsupported;
  PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, v8::Value, info,
                        receiver_check_unsupported, Getter);
316 317 318 319 320 321 322 323 324 325 326
  f(index, callback_info);
  return GetReturnValue<Object>(isolate);
}

Handle<JSObject> PropertyCallbackArguments::CallPropertyEnumerator(
    Handle<InterceptorInfo> interceptor) {
  // For now there is a single enumerator for indexed and named properties.
  IndexedPropertyEnumeratorCallback f =
      v8::ToCData<IndexedPropertyEnumeratorCallback>(interceptor->enumerator());
  // TODO(cbruni): assert same type for indexed and named callback.
  Isolate* isolate = this->isolate();
327 328 329
  Handle<Object> receiver_check_unsupported;
  PREPARE_CALLBACK_INFO(isolate, f, Handle<JSObject>, v8::Array, interceptor,
                        receiver_check_unsupported, NotAccessor);
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
  f(callback_info);
  return GetReturnValue<JSObject>(isolate);
}

// -------------------------------------------------------------------------
// Accessors

Handle<Object> PropertyCallbackArguments::CallAccessorGetter(
    Handle<AccessorInfo> info, Handle<Name> name) {
  Isolate* isolate = this->isolate();
  RuntimeCallTimerScope timer(isolate,
                              RuntimeCallCounterId::kAccessorGetterCallback);
  LOG(isolate, ApiNamedPropertyAccess("accessor-getter", holder(), *name));
  AccessorNameGetterCallback f =
      ToCData<AccessorNameGetterCallback>(info->getter());
345 346
  return BasicCallNamedGetterCallback(f, name, info,
                                      handle(receiver(), isolate));
347 348
}

349
Handle<Object> PropertyCallbackArguments::CallAccessorSetter(
350 351 352 353 354 355 356
    Handle<AccessorInfo> accessor_info, Handle<Name> name,
    Handle<Object> value) {
  Isolate* isolate = this->isolate();
  RuntimeCallTimerScope timer(isolate,
                              RuntimeCallCounterId::kAccessorSetterCallback);
  AccessorNameSetterCallback f =
      ToCData<AccessorNameSetterCallback>(accessor_info->setter());
357 358
  PREPARE_CALLBACK_INFO(isolate, f, Handle<Object>, void, accessor_info,
                        handle(receiver(), isolate), Setter);
359 360
  LOG(isolate, ApiNamedPropertyAccess("accessor-setter", holder(), *name));
  f(v8::Utils::ToLocal(name), v8::Utils::ToLocal(value), callback_info);
361
  return GetReturnValue<Object>(isolate);
362 363
}

364
#undef PREPARE_CALLBACK_INFO
365
#undef PREPARE_CALLBACK_INFO_FAIL_SIDE_EFFECT_CHECK
366

367 368
}  // namespace internal
}  // namespace v8
369 370

#endif  // V8_API_ARGUMENTS_INL_H_