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

5
#include "src/accessors.h"
6

7
#include "src/api.h"
8 9 10 11 12
#include "src/contexts.h"
#include "src/deoptimizer.h"
#include "src/execution.h"
#include "src/factory.h"
#include "src/frames-inl.h"
13
#include "src/isolate-inl.h"
14
#include "src/list-inl.h"
15
#include "src/messages.h"
16
#include "src/property-details.h"
17
#include "src/prototype.h"
18

19 20
namespace v8 {
namespace internal {
21 22


23 24
Handle<AccessorInfo> Accessors::MakeAccessor(
    Isolate* isolate,
25 26 27
    Handle<Name> name,
    AccessorNameGetterCallback getter,
    AccessorNameSetterCallback setter,
28
    PropertyAttributes attributes) {
29
  Factory* factory = isolate->factory();
30
  Handle<AccessorInfo> info = factory->NewAccessorInfo();
31
  info->set_property_attributes(attributes);
32 33
  info->set_all_can_read(false);
  info->set_all_can_write(false);
34
  info->set_is_special_data_property(true);
35
  info->set_is_sloppy(false);
36 37
  name = factory->InternalizeName(name);
  info->set_name(*name);
38
  Handle<Object> get = v8::FromCData(isolate, getter);
39
  if (setter == nullptr) setter = &ReconfigureToDataProperty;
40 41 42
  Handle<Object> set = v8::FromCData(isolate, setter);
  info->set_getter(*get);
  info->set_setter(*set);
43 44 45 46 47
  Address redirected = info->redirected_getter();
  if (redirected != nullptr) {
    Handle<Object> js_get = v8::FromCData(isolate, redirected);
    info->set_js_getter(*js_get);
  }
48 49 50 51
  return info;
}


52
static V8_INLINE bool CheckForName(Handle<Name> name,
53
                                   Handle<String> property_name,
54 55
                                   int offset,
                                   int* object_offset) {
56
  if (Name::Equals(name, property_name)) {
57 58 59 60 61 62 63
    *object_offset = offset;
    return true;
  }
  return false;
}


64 65
// Returns true for properties that are accessors to object fields.
// If true, *object_offset contains offset of object field.
66
bool Accessors::IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name,
67 68 69
                                        int* object_offset) {
  Isolate* isolate = name->GetIsolate();

70 71 72
  switch (map->instance_type()) {
    case JS_ARRAY_TYPE:
      return
73
        CheckForName(name, isolate->factory()->length_string(),
74
                     JSArray::kLengthOffset, object_offset);
75 76 77 78 79 80 81 82 83 84 85
    default:
      if (map->instance_type() < FIRST_NONSTRING_TYPE) {
        return CheckForName(name, isolate->factory()->length_string(),
                            String::kLengthOffset, object_offset);
      }

      return false;
  }
}


86 87 88 89
namespace {

MUST_USE_RESULT MaybeHandle<Object> ReplaceAccessorWithDataProperty(
    Isolate* isolate, Handle<Object> receiver, Handle<JSObject> holder,
90
    Handle<Name> name, Handle<Object> value) {
91 92 93 94 95 96 97 98
  LookupIterator it(receiver, name, holder,
                    LookupIterator::OWN_SKIP_INTERCEPTOR);
  // Skip any access checks we might hit. This accessor should never hit in a
  // situation where the caller does not have access.
  if (it.state() == LookupIterator::ACCESS_CHECK) {
    CHECK(it.HasAccess());
    it.Next();
  }
99
  DCHECK(holder.is_identical_to(it.GetHolder<JSObject>()));
100 101 102 103 104
  CHECK_EQ(LookupIterator::ACCESSOR, it.state());
  it.ReconfigureDataProperty(value, it.property_attributes());
  return value;
}

105 106
}  // namespace

107 108 109 110 111
void Accessors::ReconfigureToDataProperty(
    v8::Local<v8::Name> key, v8::Local<v8::Value> val,
    const v8::PropertyCallbackInfo<void>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
112
  Handle<Object> receiver = Utils::OpenHandle(*info.This());
113 114 115 116
  Handle<JSObject> holder =
      Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
  Handle<Name> name = Utils::OpenHandle(*key);
  Handle<Object> value = Utils::OpenHandle(*val);
117 118
  MaybeHandle<Object> result =
      ReplaceAccessorWithDataProperty(isolate, receiver, holder, name, value);
119 120
  if (result.is_null()) isolate->OptionalRescheduleException(false);
}
121

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
//
// Accessors::ArgumentsIterator
//


void Accessors::ArgumentsIteratorGetter(
    v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
  Object* result = isolate->native_context()->array_values_iterator();
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
}


Handle<AccessorInfo> Accessors::ArgumentsIteratorInfo(
    Isolate* isolate, PropertyAttributes attributes) {
139
  Handle<Name> name = isolate->factory()->iterator_symbol();
140 141
  return MakeAccessor(isolate, name, &ArgumentsIteratorGetter, nullptr,
                      attributes);
142 143 144
}


145 146 147 148 149
//
// Accessors::ArrayLength
//


150
void Accessors::ArrayLengthGetter(
151
    v8::Local<v8::Name> name,
152 153 154
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
155
  HandleScope scope(isolate);
156 157
  JSArray* holder = JSArray::cast(*Utils::OpenHandle(*info.Holder()));
  Object* result = holder->length();
158 159
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
}
160

161 162

void Accessors::ArrayLengthSetter(
163
    v8::Local<v8::Name> name,
164 165 166 167
    v8::Local<v8::Value> val,
    const v8::PropertyCallbackInfo<void>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
168

169
  Handle<JSReceiver> object = Utils::OpenHandle(*info.Holder());
170 171 172 173
  Handle<JSArray> array = Handle<JSArray>::cast(object);
  Handle<Object> length_obj = Utils::OpenHandle(*val);

  uint32_t length = 0;
174 175 176
  if (!JSArray::AnythingToArrayLength(isolate, length_obj, &length)) {
    isolate->OptionalRescheduleException(false);
    return;
177
  }
178

179
  JSArray::SetLength(array, length);
180 181 182 183 184 185 186 187 188 189 190 191 192

  if (info.ShouldThrowOnError()) {
    uint32_t actual_new_len = 0;
    CHECK(array->length()->ToArrayLength(&actual_new_len));
    // Throw TypeError if there were non-deletable elements.
    if (actual_new_len != length) {
      Factory* factory = isolate->factory();
      isolate->Throw(*factory->NewTypeError(
          MessageTemplate::kStrictDeleteProperty,
          factory->NewNumberFromUint(actual_new_len - 1), array));
      isolate->OptionalRescheduleException(false);
    }
  }
193 194 195
}


196 197 198 199 200 201 202 203 204
Handle<AccessorInfo> Accessors::ArrayLengthInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  return MakeAccessor(isolate,
                      isolate->factory()->length_string(),
                      &ArrayLengthGetter,
                      &ArrayLengthSetter,
                      attributes);
}

205 206 207 208 209

//
// Accessors::StringLength
//

210
void Accessors::StringLengthGetter(
211
    v8::Local<v8::Name> name,
212 213 214 215
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
216 217 218 219 220 221 222 223 224 225 226

  // We have a slight impedance mismatch between the external API and the way we
  // use callbacks internally: Externally, callbacks can only be used with
  // v8::Object, but internally we have callbacks on entities which are higher
  // in the hierarchy, in this case for String values.

  Object* value = *Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
  if (!value->IsString()) {
    // Not a string value. That means that we either got a String wrapper or
    // a Value with a String wrapper in its prototype chain.
    value = JSValue::cast(*Utils::OpenHandle(*info.Holder()))->value();
227
  }
228
  Object* result = Smi::FromInt(String::cast(value)->length());
229 230
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
}
231

232 233 234

Handle<AccessorInfo> Accessors::StringLengthInfo(
      Isolate* isolate, PropertyAttributes attributes) {
235 236
  return MakeAccessor(isolate, isolate->factory()->length_string(),
                      &StringLengthGetter, nullptr, attributes);
237
}
238 239 240


//
241
// Accessors::ScriptColumnOffset
242 243 244
//


245
void Accessors::ScriptColumnOffsetGetter(
246
    v8::Local<v8::Name> name,
247 248 249 250
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
251
  Object* object = *Utils::OpenHandle(*info.Holder());
252 253
  Object* res = Smi::FromInt(
      Script::cast(JSValue::cast(object)->value())->column_offset());
254
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
255 256 257
}


258 259 260
Handle<AccessorInfo> Accessors::ScriptColumnOffsetInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
261
      STATIC_CHAR_VECTOR("column_offset")));
262
  return MakeAccessor(isolate, name, &ScriptColumnOffsetGetter, nullptr,
263 264
                      attributes);
}
265 266 267


//
268
// Accessors::ScriptId
269 270 271
//


272
void Accessors::ScriptIdGetter(
273
    v8::Local<v8::Name> name,
274 275 276 277
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
278
  Object* object = *Utils::OpenHandle(*info.Holder());
279
  Object* id = Smi::FromInt(Script::cast(JSValue::cast(object)->value())->id());
280
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(id, isolate)));
281 282 283
}


284 285
Handle<AccessorInfo> Accessors::ScriptIdInfo(
      Isolate* isolate, PropertyAttributes attributes) {
286 287
  Handle<String> name(
      isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("id")));
288
  return MakeAccessor(isolate, name, &ScriptIdGetter, nullptr, attributes);
289
}
290 291


292
//
293
// Accessors::ScriptName
294 295 296
//


297
void Accessors::ScriptNameGetter(
298
    v8::Local<v8::Name> name,
299 300 301 302
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
303
  Object* object = *Utils::OpenHandle(*info.Holder());
304 305
  Object* source = Script::cast(JSValue::cast(object)->value())->name();
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate)));
306 307 308
}


309 310
Handle<AccessorInfo> Accessors::ScriptNameInfo(
      Isolate* isolate, PropertyAttributes attributes) {
311 312
  return MakeAccessor(isolate, isolate->factory()->name_string(),
                      &ScriptNameGetter, nullptr, attributes);
313
}
314 315


316
//
317
// Accessors::ScriptSource
318 319 320
//


321
void Accessors::ScriptSourceGetter(
322
    v8::Local<v8::Name> name,
323 324 325 326
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
327
  Object* object = *Utils::OpenHandle(*info.Holder());
328 329
  Object* source = Script::cast(JSValue::cast(object)->value())->source();
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate)));
330 331 332
}


333 334
Handle<AccessorInfo> Accessors::ScriptSourceInfo(
      Isolate* isolate, PropertyAttributes attributes) {
335 336
  return MakeAccessor(isolate, isolate->factory()->source_string(),
                      &ScriptSourceGetter, nullptr, attributes);
337
}
338 339 340


//
341
// Accessors::ScriptLineOffset
342 343 344
//


345
void Accessors::ScriptLineOffsetGetter(
346
    v8::Local<v8::Name> name,
347 348 349 350
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
351
  Object* object = *Utils::OpenHandle(*info.Holder());
352 353
  Object* res =
      Smi::FromInt(Script::cast(JSValue::cast(object)->value())->line_offset());
354 355 356 357 358 359 360
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
}


Handle<AccessorInfo> Accessors::ScriptLineOffsetInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
361
      STATIC_CHAR_VECTOR("line_offset")));
362
  return MakeAccessor(isolate, name, &ScriptLineOffsetGetter, nullptr,
363 364
                      attributes);
}
365 366 367 368 369 370 371


//
// Accessors::ScriptType
//


372
void Accessors::ScriptTypeGetter(
373
    v8::Local<v8::Name> name,
374 375 376 377
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
378
  Object* object = *Utils::OpenHandle(*info.Holder());
379 380
  Object* res =
      Smi::FromInt(Script::cast(JSValue::cast(object)->value())->type());
381
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
382 383 384
}


385 386
Handle<AccessorInfo> Accessors::ScriptTypeInfo(
      Isolate* isolate, PropertyAttributes attributes) {
387 388
  Handle<String> name(
      isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("type")));
389
  return MakeAccessor(isolate, name, &ScriptTypeGetter, nullptr, attributes);
390
}
391 392


393 394 395 396 397
//
// Accessors::ScriptCompilationType
//


398
void Accessors::ScriptCompilationTypeGetter(
399
    v8::Local<v8::Name> name,
400 401 402 403
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
404
  Object* object = *Utils::OpenHandle(*info.Holder());
405 406 407
  Object* res = Smi::FromInt(
      Script::cast(JSValue::cast(object)->value())->compilation_type());
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
408 409 410
}


411 412 413
Handle<AccessorInfo> Accessors::ScriptCompilationTypeInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
414
      STATIC_CHAR_VECTOR("compilation_type")));
415
  return MakeAccessor(isolate, name, &ScriptCompilationTypeGetter, nullptr,
416 417
                      attributes);
}
418 419


420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
//
// Accessors::ScriptGetLineEnds
//


void Accessors::ScriptLineEndsGetter(
    v8::Local<v8::Name> name,
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
  Handle<Object> object = Utils::OpenHandle(*info.Holder());
  Handle<Script> script(
      Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
  Script::InitLineEnds(script);
  DCHECK(script->line_ends()->IsFixedArray());
  Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
  // We do not want anyone to modify this array from JS.
  DCHECK(*line_ends == isolate->heap()->empty_fixed_array() ||
         line_ends->map() == isolate->heap()->fixed_cow_array_map());
  Handle<JSArray> js_array =
      isolate->factory()->NewJSArrayWithElements(line_ends);
  info.GetReturnValue().Set(Utils::ToLocal(js_array));
}


Handle<AccessorInfo> Accessors::ScriptLineEndsInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
      STATIC_CHAR_VECTOR("line_ends")));
  return MakeAccessor(isolate, name, &ScriptLineEndsGetter, nullptr,
                      attributes);
}


454 455 456 457 458 459
//
// Accessors::ScriptSourceUrl
//


void Accessors::ScriptSourceUrlGetter(
460
    v8::Local<v8::Name> name,
461 462 463 464
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
465
  Object* object = *Utils::OpenHandle(*info.Holder());
466 467 468 469 470 471 472
  Object* url = Script::cast(JSValue::cast(object)->value())->source_url();
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(url, isolate)));
}


Handle<AccessorInfo> Accessors::ScriptSourceUrlInfo(
      Isolate* isolate, PropertyAttributes attributes) {
473 474
  return MakeAccessor(isolate, isolate->factory()->source_url_string(),
                      &ScriptSourceUrlGetter, nullptr, attributes);
475 476 477 478 479 480 481 482 483
}


//
// Accessors::ScriptSourceMappingUrl
//


void Accessors::ScriptSourceMappingUrlGetter(
484
    v8::Local<v8::Name> name,
485 486 487 488
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
489
  Object* object = *Utils::OpenHandle(*info.Holder());
490 491 492 493 494 495 496 497
  Object* url =
      Script::cast(JSValue::cast(object)->value())->source_mapping_url();
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(url, isolate)));
}


Handle<AccessorInfo> Accessors::ScriptSourceMappingUrlInfo(
      Isolate* isolate, PropertyAttributes attributes) {
498 499
  return MakeAccessor(isolate, isolate->factory()->source_mapping_url_string(),
                      &ScriptSourceMappingUrlGetter, nullptr, attributes);
500 501 502
}


503 504 505 506 507 508 509 510 511 512
//
// Accessors::ScriptIsEmbedderDebugScript
//


void Accessors::ScriptIsEmbedderDebugScriptGetter(
    v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
513
  Object* object = *Utils::OpenHandle(*info.Holder());
514 515 516
  bool is_embedder_debug_script = Script::cast(JSValue::cast(object)->value())
                                      ->origin_options()
                                      .IsEmbedderDebugScript();
517 518 519 520 521 522 523 524 525 526
  Object* res = *isolate->factory()->ToBoolean(is_embedder_debug_script);
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
}


Handle<AccessorInfo> Accessors::ScriptIsEmbedderDebugScriptInfo(
    Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
      STATIC_CHAR_VECTOR("is_debugger_script")));
  return MakeAccessor(isolate, name, &ScriptIsEmbedderDebugScriptGetter,
527
                      nullptr, attributes);
528 529 530
}


531 532 533 534 535
//
// Accessors::ScriptGetContextData
//


536
void Accessors::ScriptContextDataGetter(
537
    v8::Local<v8::Name> name,
538 539 540 541
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
542
  Object* object = *Utils::OpenHandle(*info.Holder());
543 544
  Object* res = Script::cast(JSValue::cast(object)->value())->context_data();
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
545 546 547
}


548 549 550
Handle<AccessorInfo> Accessors::ScriptContextDataInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
551
      STATIC_CHAR_VECTOR("context_data")));
552
  return MakeAccessor(isolate, name, &ScriptContextDataGetter, nullptr,
553 554
                      attributes);
}
555 556


557
//
558
// Accessors::ScriptGetEvalFromScript
559 560 561
//


562
void Accessors::ScriptEvalFromScriptGetter(
563
    v8::Local<v8::Name> name,
564 565 566
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
567
  Handle<Object> object = Utils::OpenHandle(*info.Holder());
568 569 570
  Handle<Script> script(
      Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
  Handle<Object> result = isolate->factory()->undefined_value();
571
  if (!script->eval_from_shared()->IsUndefined(isolate)) {
572
    Handle<SharedFunctionInfo> eval_from_shared(
573
        SharedFunctionInfo::cast(script->eval_from_shared()));
574 575
    if (eval_from_shared->script()->IsScript()) {
      Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
576
      result = Script::GetWrapper(eval_from_script);
577 578
    }
  }
579 580

  info.GetReturnValue().Set(Utils::ToLocal(result));
581 582 583
}


584 585 586
Handle<AccessorInfo> Accessors::ScriptEvalFromScriptInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
587
      STATIC_CHAR_VECTOR("eval_from_script")));
588
  return MakeAccessor(isolate, name, &ScriptEvalFromScriptGetter, nullptr,
589 590
                      attributes);
}
591 592 593


//
594
// Accessors::ScriptGetEvalFromScriptPosition
595 596 597
//


598
void Accessors::ScriptEvalFromScriptPositionGetter(
599
    v8::Local<v8::Name> name,
600 601
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
602
  HandleScope scope(isolate);
603
  Handle<Object> object = Utils::OpenHandle(*info.Holder());
604 605 606 607
  Handle<Script> script(
      Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
  Handle<Object> result = isolate->factory()->undefined_value();
  if (script->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
608
    result = Handle<Object>(Smi::FromInt(script->GetEvalPosition()), isolate);
609
  }
610 611 612
  info.GetReturnValue().Set(Utils::ToLocal(result));
}

613

614 615 616
Handle<AccessorInfo> Accessors::ScriptEvalFromScriptPositionInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
617
      STATIC_CHAR_VECTOR("eval_from_script_position")));
618 619
  return MakeAccessor(isolate, name, &ScriptEvalFromScriptPositionGetter,
                      nullptr, attributes);
620
}
621 622 623 624 625 626 627


//
// Accessors::ScriptGetEvalFromFunctionName
//


628
void Accessors::ScriptEvalFromFunctionNameGetter(
629
    v8::Local<v8::Name> name,
630 631 632
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
633
  Handle<Object> object = Utils::OpenHandle(*info.Holder());
634 635
  Handle<Script> script(
      Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
636
  Handle<Object> result = isolate->factory()->undefined_value();
637
  if (!script->eval_from_shared()->IsUndefined(isolate)) {
638 639 640
    Handle<SharedFunctionInfo> shared(
        SharedFunctionInfo::cast(script->eval_from_shared()));
    // Find the name of the function calling eval.
641
    if (!shared->name()->IsUndefined(isolate)) {
642 643 644 645
      result = Handle<Object>(shared->name(), isolate);
    } else {
      result = Handle<Object>(shared->inferred_name(), isolate);
    }
646
  }
647
  info.GetReturnValue().Set(Utils::ToLocal(result));
648 649 650
}


651 652 653
Handle<AccessorInfo> Accessors::ScriptEvalFromFunctionNameInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
654
      STATIC_CHAR_VECTOR("eval_from_function_name")));
655
  return MakeAccessor(isolate, name, &ScriptEvalFromFunctionNameGetter, nullptr,
656 657
                      attributes);
}
658 659


660 661 662 663
//
// Accessors::FunctionPrototype
//

664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
static Handle<Object> GetFunctionPrototype(Isolate* isolate,
                                           Handle<JSFunction> function) {
  if (!function->has_prototype()) {
    Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function);
    JSFunction::SetPrototype(function, proto);
  }
  return Handle<Object>(function->prototype(), isolate);
}


MUST_USE_RESULT static MaybeHandle<Object> SetFunctionPrototype(
    Isolate* isolate, Handle<JSFunction> function, Handle<Object> value) {
  JSFunction::SetPrototype(function, value);
  DCHECK(function->prototype() == *value);
  return function;
}


682 683
MaybeHandle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function,
                                                    Handle<Object> prototype) {
684 685 686
  DCHECK(function->IsConstructor());
  Isolate* isolate = function->GetIsolate();
  return SetFunctionPrototype(isolate, function, prototype);
687 688 689
}


690
void Accessors::FunctionPrototypeGetter(
691
    v8::Local<v8::Name> name,
692 693
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
694
  HandleScope scope(isolate);
695 696
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
697
  Handle<Object> result = GetFunctionPrototype(isolate, function);
698
  info.GetReturnValue().Set(Utils::ToLocal(result));
699 700 701
}


702
void Accessors::FunctionPrototypeSetter(
703
    v8::Local<v8::Name> name,
704 705 706 707 708
    v8::Local<v8::Value> val,
    const v8::PropertyCallbackInfo<void>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
  Handle<Object> value = Utils::OpenHandle(*val);
709 710
  Handle<JSFunction> object =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
711 712 713
  if (SetFunctionPrototype(isolate, object, value).is_null()) {
    isolate->OptionalRescheduleException(false);
  }
714 715 716
}


717 718 719 720 721 722 723 724
Handle<AccessorInfo> Accessors::FunctionPrototypeInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  return MakeAccessor(isolate,
                      isolate->factory()->prototype_string(),
                      &FunctionPrototypeGetter,
                      &FunctionPrototypeSetter,
                      attributes);
}
725 726 727 728 729 730 731


//
// Accessors::FunctionLength
//


732
void Accessors::FunctionLengthGetter(
733
    v8::Local<v8::Name> name,
734 735
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
736
  HandleScope scope(isolate);
737 738
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
739 740 741 742
  Handle<Object> result;
  if (!JSFunction::GetLength(isolate, function).ToHandle(&result)) {
    result = handle(Smi::FromInt(0), isolate);
    isolate->OptionalRescheduleException(false);
743
  }
744

745
  info.GetReturnValue().Set(Utils::ToLocal(result));
746 747
}

748 749
Handle<AccessorInfo> Accessors::FunctionLengthInfo(
      Isolate* isolate, PropertyAttributes attributes) {
750
  return MakeAccessor(isolate, isolate->factory()->length_string(),
751
                      &FunctionLengthGetter, &ReconfigureToDataProperty,
752 753
                      attributes);
}
754 755 756 757 758 759 760


//
// Accessors::FunctionName
//


761
void Accessors::FunctionNameGetter(
762
    v8::Local<v8::Name> name,
763 764 765
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
766 767
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
768
  Handle<Object> result = JSFunction::GetName(isolate, function);
769
  info.GetReturnValue().Set(Utils::ToLocal(result));
770 771
}

772 773
Handle<AccessorInfo> Accessors::FunctionNameInfo(
      Isolate* isolate, PropertyAttributes attributes) {
774
  return MakeAccessor(isolate, isolate->factory()->name_string(),
775
                      &FunctionNameGetter, &ReconfigureToDataProperty,
776 777
                      attributes);
}
778 779 780 781 782 783


//
// Accessors::FunctionArguments
//

784

785
static Handle<Object> ArgumentsForInlinedFunction(
786 787 788
    JavaScriptFrame* frame,
    Handle<JSFunction> inlined_function,
    int inlined_frame_index) {
789 790
  Isolate* isolate = inlined_function->GetIsolate();
  Factory* factory = isolate->factory();
jarin@chromium.org's avatar
jarin@chromium.org committed
791

792 793 794 795 796 797 798 799 800
  TranslatedState translated_values(frame);
  translated_values.Prepare(false, frame->fp());

  int argument_count = 0;
  TranslatedFrame* translated_frame =
      translated_values.GetArgumentsInfoFromJSFrameIndex(inlined_frame_index,
                                                         &argument_count);
  TranslatedFrame::iterator iter = translated_frame->begin();

801 802 803
  // Skip the function.
  iter++;

804 805 806 807
  // Skip the receiver.
  iter++;
  argument_count--;

808
  Handle<JSObject> arguments =
809 810 811 812 813 814 815 816
      factory->NewArgumentsObject(inlined_function, argument_count);
  Handle<FixedArray> array = factory->NewFixedArray(argument_count);
  bool should_deoptimize = false;
  for (int i = 0; i < argument_count; ++i) {
    // If we materialize any object, we should deopt because we might alias
    // an object that was eliminated by escape analysis.
    should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
    Handle<Object> value = iter->GetValue();
817
    array->set(i, *value);
818
    iter++;
819 820 821
  }
  arguments->set_elements(*array);

822 823 824 825
  if (should_deoptimize) {
    translated_values.StoreMaterializedValuesAndDeopt();
  }

826
  // Return the freshly allocated arguments object.
827
  return arguments;
828 829
}

830

831 832 833 834 835 836 837 838 839 840 841 842
static int FindFunctionInFrame(JavaScriptFrame* frame,
                               Handle<JSFunction> function) {
  DisallowHeapAllocation no_allocation;
  List<JSFunction*> functions(2);
  frame->GetFunctions(&functions);
  for (int i = functions.length() - 1; i >= 0; i--) {
    if (functions[i] == *function) return i;
  }
  return -1;
}


843 844
namespace {

845 846
Handle<Object> GetFunctionArguments(Isolate* isolate,
                                    Handle<JSFunction> function) {
847
  // Find the top invocation of the function by traversing frames.
848
  for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
849
    JavaScriptFrame* frame = it.frame();
850 851 852 853 854 855 856 857 858 859
    int function_index = FindFunctionInFrame(frame, function);
    if (function_index < 0) continue;

    if (function_index > 0) {
      // The function in question was inlined.  Inlined functions have the
      // correct number of arguments and no allocated arguments object, so
      // we can construct a fresh one by interpreting the function's
      // deoptimization input data.
      return ArgumentsForInlinedFunction(frame, function, function_index);
    }
860

861
    // Find the frame that holds the actual arguments passed to the function.
862 863 864 865 866 867 868 869 870 871 872
    it.AdvanceToArgumentsFrame();
    frame = it.frame();

    // Get the number of arguments and construct an arguments object
    // mirror for the right frame.
    const int length = frame->ComputeParametersCount();
    Handle<JSObject> arguments = isolate->factory()->NewArgumentsObject(
        function, length);
    Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);

    // Copy the parameters to the arguments object.
873
    DCHECK(array->length() == length);
874 875 876 877 878 879 880 881 882 883
    for (int i = 0; i < length; i++) {
      Object* value = frame->GetParameter(i);
      if (value->IsTheHole(isolate)) {
        // Generators currently use holes as dummy arguments when resuming.  We
        // must not leak those.
        DCHECK(IsResumableFunction(function->shared()->kind()));
        value = isolate->heap()->undefined_value();
      }
      array->set(i, value);
    }
884 885 886 887
    arguments->set_elements(*array);

    // Return the freshly allocated arguments object.
    return arguments;
888 889 890
  }

  // No frame corresponding to the given function found. Return null.
891 892 893
  return isolate->factory()->null_value();
}

894 895
}  // namespace

896

897 898 899 900 901
Handle<JSObject> Accessors::FunctionGetArguments(Handle<JSFunction> function) {
  Handle<Object> arguments =
      GetFunctionArguments(function->GetIsolate(), function);
  CHECK(arguments->IsJSObject());
  return Handle<JSObject>::cast(arguments);
902 903 904
}


905
void Accessors::FunctionArgumentsGetter(
906
    v8::Local<v8::Name> name,
907 908
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
909
  HandleScope scope(isolate);
910 911
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
912 913 914 915
  Handle<Object> result =
      function->shared()->native()
          ? Handle<Object>::cast(isolate->factory()->null_value())
          : GetFunctionArguments(isolate, function);
916
  info.GetReturnValue().Set(Utils::ToLocal(result));
917 918 919
}


920 921
Handle<AccessorInfo> Accessors::FunctionArgumentsInfo(
      Isolate* isolate, PropertyAttributes attributes) {
922 923
  return MakeAccessor(isolate, isolate->factory()->arguments_string(),
                      &FunctionArgumentsGetter, nullptr, attributes);
924
}
925 926 927 928 929 930 931


//
// Accessors::FunctionCaller
//


932 933 934 935 936 937
static inline bool AllowAccessToFunction(Context* current_context,
                                         JSFunction* function) {
  return current_context->HasSameSecurityTokenAs(function->context());
}


938 939
class FrameFunctionIterator {
 public:
940
  FrameFunctionIterator(Isolate* isolate, const DisallowHeapAllocation& promise)
941 942
      : isolate_(isolate),
        frame_iterator_(isolate),
943 944 945 946 947
        functions_(2),
        index_(0) {
    GetFunctions();
  }
  JSFunction* next() {
948 949 950 951 952 953 954 955 956 957
    while (true) {
      if (functions_.length() == 0) return NULL;
      JSFunction* next_function = functions_[index_];
      index_--;
      if (index_ < 0) {
        GetFunctions();
      }
      // Skip functions from other origins.
      if (!AllowAccessToFunction(isolate_->context(), next_function)) continue;
      return next_function;
958 959 960 961 962 963 964 965 966 967 968 969 970 971
    }
  }

  // Iterate through functions until the first occurence of 'function'.
  // Returns true if 'function' is found, and false if the iterator ends
  // without finding it.
  bool Find(JSFunction* function) {
    JSFunction* next_function;
    do {
      next_function = next();
      if (next_function == function) return true;
    } while (next_function != NULL);
    return false;
  }
972

973 974 975 976 977 978
 private:
  void GetFunctions() {
    functions_.Rewind(0);
    if (frame_iterator_.done()) return;
    JavaScriptFrame* frame = frame_iterator_.frame();
    frame->GetFunctions(&functions_);
979
    DCHECK(functions_.length() > 0);
980 981 982
    frame_iterator_.Advance();
    index_ = functions_.length() - 1;
  }
983
  Isolate* isolate_;
984 985 986 987 988 989
  JavaScriptFrameIterator frame_iterator_;
  List<JSFunction*> functions_;
  int index_;
};


990 991
MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
                                   Handle<JSFunction> function) {
992 993
  DisallowHeapAllocation no_allocation;
  FrameFunctionIterator it(isolate, no_allocation);
994 995 996
  if (function->shared()->native()) {
    return MaybeHandle<JSFunction>();
  }
997 998 999
  // Find the function from the frames.
  if (!it.Find(*function)) {
    // No frame corresponding to the given function found. Return null.
1000
    return MaybeHandle<JSFunction>();
1001
  }
1002 1003 1004 1005
  // Find previously called non-toplevel function.
  JSFunction* caller;
  do {
    caller = it.next();
1006
    if (caller == NULL) return MaybeHandle<JSFunction>();
1007 1008 1009 1010 1011
  } while (caller->shared()->is_toplevel());

  // If caller is a built-in function and caller's caller is also built-in,
  // use that instead.
  JSFunction* potential_caller = caller;
1012
  while (potential_caller != NULL && potential_caller->shared()->IsBuiltin()) {
1013 1014 1015
    caller = potential_caller;
    potential_caller = it.next();
  }
1016 1017 1018
  if (!caller->shared()->native() && potential_caller != NULL) {
    caller = potential_caller;
  }
1019
  // Censor if the caller is not a sloppy mode function.
1020 1021
  // Change from ES5, which used to throw, see:
  // https://bugs.ecmascript.org/show_bug.cgi?id=310
1022
  if (is_strict(caller->shared()->language_mode())) {
1023 1024
    return MaybeHandle<JSFunction>();
  }
1025 1026 1027 1028
  // Don't return caller from another security context.
  if (!AllowAccessToFunction(isolate->context(), caller)) {
    return MaybeHandle<JSFunction>();
  }
1029 1030 1031 1032 1033
  return Handle<JSFunction>(caller);
}


void Accessors::FunctionCallerGetter(
1034
    v8::Local<v8::Name> name,
1035 1036 1037
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
1038 1039
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
1040
  Handle<Object> result;
1041 1042 1043 1044 1045
  MaybeHandle<JSFunction> maybe_caller;
  maybe_caller = FindCaller(isolate, function);
  Handle<JSFunction> caller;
  if (maybe_caller.ToHandle(&caller)) {
    result = caller;
1046
  } else {
1047
    result = isolate->factory()->null_value();
1048
  }
1049 1050 1051
  info.GetReturnValue().Set(Utils::ToLocal(result));
}

1052

1053 1054
Handle<AccessorInfo> Accessors::FunctionCallerInfo(
      Isolate* isolate, PropertyAttributes attributes) {
1055 1056
  return MakeAccessor(isolate, isolate->factory()->caller_string(),
                      &FunctionCallerGetter, nullptr, attributes);
1057
}
1058 1059


1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
//
// Accessors::BoundFunctionLength
//

void Accessors::BoundFunctionLengthGetter(
    v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
  Handle<JSBoundFunction> function =
      Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));

  Handle<Smi> target_length;
  Handle<JSFunction> target(JSFunction::cast(function->bound_target_function()),
                            isolate);
  if (!JSFunction::GetLength(isolate, target).ToHandle(&target_length)) {
    target_length = handle(Smi::FromInt(0), isolate);
    isolate->OptionalRescheduleException(false);
    return;
  }

  int bound_length = function->bound_arguments()->length();
  int length = Max(0, target_length->value() - bound_length);

  Handle<Object> result(Smi::FromInt(length), isolate);
  info.GetReturnValue().Set(Utils::ToLocal(result));
}

Handle<AccessorInfo> Accessors::BoundFunctionLengthInfo(
    Isolate* isolate, PropertyAttributes attributes) {
  return MakeAccessor(isolate, isolate->factory()->length_string(),
1090 1091
                      &BoundFunctionLengthGetter, &ReconfigureToDataProperty,
                      attributes);
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
}

//
// Accessors::BoundFunctionName
//

void Accessors::BoundFunctionNameGetter(
    v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
  Handle<JSBoundFunction> function =
      Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
  Handle<Object> result;
  if (!JSBoundFunction::GetName(isolate, function).ToHandle(&result)) {
    isolate->OptionalRescheduleException(false);
    return;
  }
  info.GetReturnValue().Set(Utils::ToLocal(result));
}

Handle<AccessorInfo> Accessors::BoundFunctionNameInfo(
    Isolate* isolate, PropertyAttributes attributes) {
  return MakeAccessor(isolate, isolate->factory()->name_string(),
1115 1116
                      &BoundFunctionNameGetter, &ReconfigureToDataProperty,
                      attributes);
1117 1118
}

jgruber's avatar
jgruber committed
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
//
// Accessors::ErrorStack
//

namespace {

MaybeHandle<JSReceiver> ClearInternalStackTrace(Isolate* isolate,
                                                Handle<JSObject> error) {
  RETURN_ON_EXCEPTION(
      isolate,
      JSReceiver::SetProperty(error, isolate->factory()->stack_trace_symbol(),
                              isolate->factory()->undefined_value(), STRICT),
      JSReceiver);
  return error;
}

bool IsAccessor(Handle<Object> receiver, Handle<Name> name,
                Handle<JSObject> holder) {
  LookupIterator it(receiver, name, holder,
                    LookupIterator::OWN_SKIP_INTERCEPTOR);
  // Skip any access checks we might hit. This accessor should never hit in a
  // situation where the caller does not have access.
  if (it.state() == LookupIterator::ACCESS_CHECK) {
    CHECK(it.HasAccess());
    it.Next();
  }
  return (it.state() == LookupIterator::ACCESSOR);
}

}  // namespace

void Accessors::ErrorStackGetter(
    v8::Local<v8::Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
  Handle<JSObject> holder =
      Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));

  // Retrieve the structured stack trace.

  Handle<Object> stack_trace;
  Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
  MaybeHandle<Object> maybe_stack_trace =
      JSObject::GetProperty(holder, stack_trace_symbol);
  if (!maybe_stack_trace.ToHandle(&stack_trace) ||
      stack_trace->IsUndefined(isolate)) {
    Handle<Object> result = isolate->factory()->undefined_value();
    info.GetReturnValue().Set(Utils::ToLocal(result));
    return;
  }

  // Format it, clear the internal structured trace and reconfigure as a data
  // property.

  Handle<Object> formatted_stack_trace;
1174
  if (!ErrorUtils::FormatStackTrace(isolate, holder, stack_trace)
jgruber's avatar
jgruber committed
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
           .ToHandle(&formatted_stack_trace)) {
    isolate->OptionalRescheduleException(false);
    return;
  }

  MaybeHandle<Object> result = ClearInternalStackTrace(isolate, holder);
  if (result.is_null()) {
    isolate->OptionalRescheduleException(false);
    return;
  }

  // If stack is still an accessor (this could have changed in the meantime
  // since FormatStackTrace can execute arbitrary JS), replace it with a data
  // property.
  Handle<Object> receiver = Utils::OpenHandle(*info.This());
  Handle<Name> name = Utils::OpenHandle(*key);
  if (IsAccessor(receiver, name, holder)) {
    result = ReplaceAccessorWithDataProperty(isolate, receiver, holder, name,
                                             formatted_stack_trace);
    if (result.is_null()) {
      isolate->OptionalRescheduleException(false);
      return;
    }
  } else {
    // The stack property has been modified in the meantime.
    if (!JSObject::GetProperty(holder, name).ToHandle(&formatted_stack_trace)) {
      isolate->OptionalRescheduleException(false);
      return;
    }
  }

  v8::Local<v8::Value> value = Utils::ToLocal(formatted_stack_trace);
  info.GetReturnValue().Set(value);
}

void Accessors::ErrorStackSetter(v8::Local<v8::Name> name,
                                 v8::Local<v8::Value> val,
                                 const v8::PropertyCallbackInfo<void>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
  Handle<JSObject> obj =
      Handle<JSObject>::cast(Utils::OpenHandle(*info.This()));

  // Clear internal properties to avoid memory leaks.
  Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
  if (JSReceiver::HasOwnProperty(obj, stack_trace_symbol).FromMaybe(false)) {
    ClearInternalStackTrace(isolate, obj);
  }

  Accessors::ReconfigureToDataProperty(name, val, info);
}

Handle<AccessorInfo> Accessors::ErrorStackInfo(Isolate* isolate,
                                               PropertyAttributes attributes) {
  Handle<AccessorInfo> info =
      MakeAccessor(isolate, isolate->factory()->stack_string(),
                   &ErrorStackGetter, &ErrorStackSetter, attributes);
  return info;
}
1234

1235 1236
}  // namespace internal
}  // namespace v8