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


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


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

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

      return false;
  }
}


83 84 85 86
namespace {

MUST_USE_RESULT MaybeHandle<Object> ReplaceAccessorWithDataProperty(
    Isolate* isolate, Handle<Object> receiver, Handle<JSObject> holder,
87
    Handle<Name> name, Handle<Object> value) {
88 89 90 91 92 93 94 95
  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();
  }
96
  DCHECK(holder.is_identical_to(it.GetHolder<JSObject>()));
97 98 99 100 101
  CHECK_EQ(LookupIterator::ACCESSOR, it.state());
  it.ReconfigureDataProperty(value, it.property_attributes());
  return value;
}

102 103
}  // namespace

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

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
//
// 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) {
140
  Handle<Name> name = isolate->factory()->iterator_symbol();
141 142
  return MakeAccessor(isolate, name, &ArgumentsIteratorGetter, nullptr,
                      attributes);
143 144 145
}


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


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

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

170 171
  DCHECK(Utils::OpenHandle(*name)->SameValue(isolate->heap()->length_string()));

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

176 177
  bool was_readonly = JSArray::HasReadOnlyLength(array);

178
  uint32_t length = 0;
179 180 181
  if (!JSArray::AnythingToArrayLength(isolate, length_obj, &length)) {
    isolate->OptionalRescheduleException(false);
    return;
182
  }
183

184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
  if (!was_readonly && V8_UNLIKELY(JSArray::HasReadOnlyLength(array)) &&
      length != array->length()->Number()) {
    // AnythingToArrayLength() may have called setter re-entrantly and modified
    // its property descriptor. Don't perform this check if "length" was
    // previously readonly, as this may have been called during
    // DefineOwnPropertyIgnoreAttributes().
    if (info.ShouldThrowOnError()) {
      Factory* factory = isolate->factory();
      isolate->Throw(*factory->NewTypeError(
          MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
          i::Object::TypeOf(isolate, object), object));
      isolate->OptionalRescheduleException(false);
    } else {
      info.GetReturnValue().Set(false);
    }
    return;
  }

202
  JSArray::SetLength(array, length);
203

204 205 206 207 208
  uint32_t actual_new_len = 0;
  CHECK(array->length()->ToArrayLength(&actual_new_len));
  // Fail if there were non-deletable elements.
  if (actual_new_len != length) {
    if (info.ShouldThrowOnError()) {
209 210 211 212 213
      Factory* factory = isolate->factory();
      isolate->Throw(*factory->NewTypeError(
          MessageTemplate::kStrictDeleteProperty,
          factory->NewNumberFromUint(actual_new_len - 1), array));
      isolate->OptionalRescheduleException(false);
214 215
    } else {
      info.GetReturnValue().Set(false);
216
    }
217 218
  } else {
    info.GetReturnValue().Set(true);
219
  }
220 221 222
}


223 224 225 226 227 228 229
Handle<AccessorInfo> Accessors::ArrayLengthInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  return MakeAccessor(isolate,
                      isolate->factory()->length_string(),
                      &ArrayLengthGetter,
                      &ArrayLengthSetter,
                      attributes);
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
}

//
// Accessors::ModuleNamespaceEntry
//

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

void Accessors::ModuleNamespaceEntrySetter(
    v8::Local<v8::Name> name, v8::Local<v8::Value> val,
253
    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
254 255 256 257 258 259 260 261 262 263 264 265
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
  Factory* factory = isolate->factory();
  Handle<JSModuleNamespace> holder =
      Handle<JSModuleNamespace>::cast(Utils::OpenHandle(*info.Holder()));

  if (info.ShouldThrowOnError()) {
    isolate->Throw(*factory->NewTypeError(
        MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
        i::Object::TypeOf(isolate, holder), holder));
    isolate->OptionalRescheduleException(false);
  } else {
266
    info.GetReturnValue().Set(false);
267 268 269 270 271 272 273
  }
}

Handle<AccessorInfo> Accessors::ModuleNamespaceEntryInfo(
    Isolate* isolate, Handle<String> name, PropertyAttributes attributes) {
  return MakeAccessor(isolate, name, &ModuleNamespaceEntryGetter,
                      &ModuleNamespaceEntrySetter, attributes);
274 275
}

276 277 278 279 280

//
// Accessors::StringLength
//

281
void Accessors::StringLengthGetter(
282
    v8::Local<v8::Name> name,
283 284
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
285 286
  RuntimeCallTimerScope timer(
      isolate, &RuntimeCallStats::AccessorNameGetterCallback_StringLength);
287 288
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
289 290 291 292 293 294 295 296 297 298 299

  // 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();
300
  }
301
  Object* result = Smi::FromInt(String::cast(value)->length());
302 303
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
}
304

305 306 307

Handle<AccessorInfo> Accessors::StringLengthInfo(
      Isolate* isolate, PropertyAttributes attributes) {
308 309
  return MakeAccessor(isolate, isolate->factory()->length_string(),
                      &StringLengthGetter, nullptr, attributes);
310
}
311 312 313


//
314
// Accessors::ScriptColumnOffset
315 316 317
//


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


331 332 333
Handle<AccessorInfo> Accessors::ScriptColumnOffsetInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
334
      STATIC_CHAR_VECTOR("column_offset")));
335
  return MakeAccessor(isolate, name, &ScriptColumnOffsetGetter, nullptr,
336 337
                      attributes);
}
338 339 340


//
341
// Accessors::ScriptId
342 343 344
//


345
void Accessors::ScriptIdGetter(
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
  Object* id = Smi::FromInt(Script::cast(JSValue::cast(object)->value())->id());
353
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(id, isolate)));
354 355 356
}


357 358
Handle<AccessorInfo> Accessors::ScriptIdInfo(
      Isolate* isolate, PropertyAttributes attributes) {
359 360
  Handle<String> name(
      isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("id")));
361
  return MakeAccessor(isolate, name, &ScriptIdGetter, nullptr, attributes);
362
}
363 364


365
//
366
// Accessors::ScriptName
367 368 369
//


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


382 383
Handle<AccessorInfo> Accessors::ScriptNameInfo(
      Isolate* isolate, PropertyAttributes attributes) {
384 385
  return MakeAccessor(isolate, isolate->factory()->name_string(),
                      &ScriptNameGetter, nullptr, attributes);
386
}
387 388


389
//
390
// Accessors::ScriptSource
391 392 393
//


394
void Accessors::ScriptSourceGetter(
395
    v8::Local<v8::Name> name,
396 397 398 399
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
400
  Object* object = *Utils::OpenHandle(*info.Holder());
401 402
  Object* source = Script::cast(JSValue::cast(object)->value())->source();
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate)));
403 404 405
}


406 407
Handle<AccessorInfo> Accessors::ScriptSourceInfo(
      Isolate* isolate, PropertyAttributes attributes) {
408 409
  return MakeAccessor(isolate, isolate->factory()->source_string(),
                      &ScriptSourceGetter, nullptr, attributes);
410
}
411 412 413


//
414
// Accessors::ScriptLineOffset
415 416 417
//


418
void Accessors::ScriptLineOffsetGetter(
419
    v8::Local<v8::Name> name,
420 421 422 423
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
424
  Object* object = *Utils::OpenHandle(*info.Holder());
425 426
  Object* res =
      Smi::FromInt(Script::cast(JSValue::cast(object)->value())->line_offset());
427 428 429 430 431 432 433
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
}


Handle<AccessorInfo> Accessors::ScriptLineOffsetInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
434
      STATIC_CHAR_VECTOR("line_offset")));
435
  return MakeAccessor(isolate, name, &ScriptLineOffsetGetter, nullptr,
436 437
                      attributes);
}
438 439 440 441 442 443 444


//
// Accessors::ScriptType
//


445
void Accessors::ScriptTypeGetter(
446
    v8::Local<v8::Name> name,
447 448 449 450
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
451
  Object* object = *Utils::OpenHandle(*info.Holder());
452 453
  Object* res =
      Smi::FromInt(Script::cast(JSValue::cast(object)->value())->type());
454
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
455 456 457
}


458 459
Handle<AccessorInfo> Accessors::ScriptTypeInfo(
      Isolate* isolate, PropertyAttributes attributes) {
460 461
  Handle<String> name(
      isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("type")));
462
  return MakeAccessor(isolate, name, &ScriptTypeGetter, nullptr, attributes);
463
}
464 465


466 467 468 469 470
//
// Accessors::ScriptCompilationType
//


471
void Accessors::ScriptCompilationTypeGetter(
472
    v8::Local<v8::Name> name,
473 474 475 476
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
477
  Object* object = *Utils::OpenHandle(*info.Holder());
478 479 480
  Object* res = Smi::FromInt(
      Script::cast(JSValue::cast(object)->value())->compilation_type());
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
481 482 483
}


484 485 486
Handle<AccessorInfo> Accessors::ScriptCompilationTypeInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
487
      STATIC_CHAR_VECTOR("compilation_type")));
488
  return MakeAccessor(isolate, name, &ScriptCompilationTypeGetter, nullptr,
489 490
                      attributes);
}
491 492


493 494 495 496 497 498
//
// Accessors::ScriptSourceUrl
//


void Accessors::ScriptSourceUrlGetter(
499
    v8::Local<v8::Name> name,
500 501 502 503
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
504
  Object* object = *Utils::OpenHandle(*info.Holder());
505 506 507 508 509 510 511
  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) {
512 513
  return MakeAccessor(isolate, isolate->factory()->source_url_string(),
                      &ScriptSourceUrlGetter, nullptr, attributes);
514 515 516 517 518 519 520 521 522
}


//
// Accessors::ScriptSourceMappingUrl
//


void Accessors::ScriptSourceMappingUrlGetter(
523
    v8::Local<v8::Name> name,
524 525 526 527
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
528
  Object* object = *Utils::OpenHandle(*info.Holder());
529 530 531 532 533 534 535 536
  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) {
537 538
  return MakeAccessor(isolate, isolate->factory()->source_mapping_url_string(),
                      &ScriptSourceMappingUrlGetter, nullptr, attributes);
539 540 541
}


542 543 544 545 546
//
// Accessors::ScriptGetContextData
//


547
void Accessors::ScriptContextDataGetter(
548
    v8::Local<v8::Name> name,
549 550 551 552
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  DisallowHeapAllocation no_allocation;
  HandleScope scope(isolate);
553
  Object* object = *Utils::OpenHandle(*info.Holder());
554 555
  Object* res = Script::cast(JSValue::cast(object)->value())->context_data();
  info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
556 557 558
}


559 560 561
Handle<AccessorInfo> Accessors::ScriptContextDataInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
562
      STATIC_CHAR_VECTOR("context_data")));
563
  return MakeAccessor(isolate, name, &ScriptContextDataGetter, nullptr,
564 565
                      attributes);
}
566 567


568
//
569
// Accessors::ScriptGetEvalFromScript
570 571 572
//


573
void Accessors::ScriptEvalFromScriptGetter(
574
    v8::Local<v8::Name> name,
575 576 577
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
578
  Handle<Object> object = Utils::OpenHandle(*info.Holder());
579 580 581
  Handle<Script> script(
      Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
  Handle<Object> result = isolate->factory()->undefined_value();
582
  if (!script->eval_from_shared()->IsUndefined(isolate)) {
583
    Handle<SharedFunctionInfo> eval_from_shared(
584
        SharedFunctionInfo::cast(script->eval_from_shared()));
585 586
    if (eval_from_shared->script()->IsScript()) {
      Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
587
      result = Script::GetWrapper(eval_from_script);
588 589
    }
  }
590 591

  info.GetReturnValue().Set(Utils::ToLocal(result));
592 593 594
}


595 596 597
Handle<AccessorInfo> Accessors::ScriptEvalFromScriptInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
598
      STATIC_CHAR_VECTOR("eval_from_script")));
599
  return MakeAccessor(isolate, name, &ScriptEvalFromScriptGetter, nullptr,
600 601
                      attributes);
}
602 603 604


//
605
// Accessors::ScriptGetEvalFromScriptPosition
606 607 608
//


609
void Accessors::ScriptEvalFromScriptPositionGetter(
610
    v8::Local<v8::Name> name,
611 612
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
613
  HandleScope scope(isolate);
614
  Handle<Object> object = Utils::OpenHandle(*info.Holder());
615 616 617 618
  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) {
619
    result = Handle<Object>(Smi::FromInt(script->GetEvalPosition()), isolate);
620
  }
621 622 623
  info.GetReturnValue().Set(Utils::ToLocal(result));
}

624

625 626 627
Handle<AccessorInfo> Accessors::ScriptEvalFromScriptPositionInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
628
      STATIC_CHAR_VECTOR("eval_from_script_position")));
629 630
  return MakeAccessor(isolate, name, &ScriptEvalFromScriptPositionGetter,
                      nullptr, attributes);
631
}
632 633 634 635 636 637 638


//
// Accessors::ScriptGetEvalFromFunctionName
//


639
void Accessors::ScriptEvalFromFunctionNameGetter(
640
    v8::Local<v8::Name> name,
641 642 643
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
644
  Handle<Object> object = Utils::OpenHandle(*info.Holder());
645 646
  Handle<Script> script(
      Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
647
  Handle<Object> result = isolate->factory()->undefined_value();
648
  if (!script->eval_from_shared()->IsUndefined(isolate)) {
649 650 651
    Handle<SharedFunctionInfo> shared(
        SharedFunctionInfo::cast(script->eval_from_shared()));
    // Find the name of the function calling eval.
652
    if (!shared->name()->IsUndefined(isolate)) {
653 654 655 656
      result = Handle<Object>(shared->name(), isolate);
    } else {
      result = Handle<Object>(shared->inferred_name(), isolate);
    }
657
  }
658
  info.GetReturnValue().Set(Utils::ToLocal(result));
659 660 661
}


662 663 664
Handle<AccessorInfo> Accessors::ScriptEvalFromFunctionNameInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  Handle<String> name(isolate->factory()->InternalizeOneByteString(
665
      STATIC_CHAR_VECTOR("eval_from_function_name")));
666
  return MakeAccessor(isolate, name, &ScriptEvalFromFunctionNameGetter, nullptr,
667 668
                      attributes);
}
669 670


671 672 673 674
//
// Accessors::FunctionPrototype
//

675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
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;
}


693 694
MaybeHandle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function,
                                                    Handle<Object> prototype) {
695 696 697
  DCHECK(function->IsConstructor());
  Isolate* isolate = function->GetIsolate();
  return SetFunctionPrototype(isolate, function, prototype);
698 699 700
}


701
void Accessors::FunctionPrototypeGetter(
702
    v8::Local<v8::Name> name,
703 704
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
705 706
  RuntimeCallTimerScope timer(
      isolate, &RuntimeCallStats::AccessorNameGetterCallback_FunctionPrototype);
707
  HandleScope scope(isolate);
708 709
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
710
  Handle<Object> result = GetFunctionPrototype(isolate, function);
711
  info.GetReturnValue().Set(Utils::ToLocal(result));
712 713
}

714
void Accessors::FunctionPrototypeSetter(
715 716
    v8::Local<v8::Name> name, v8::Local<v8::Value> val,
    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
717 718 719
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
  Handle<Object> value = Utils::OpenHandle(*val);
720 721
  Handle<JSFunction> object =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
722 723
  if (SetFunctionPrototype(isolate, object, value).is_null()) {
    isolate->OptionalRescheduleException(false);
724 725
  } else {
    info.GetReturnValue().Set(true);
726
  }
727 728 729
}


730 731 732 733 734 735 736 737
Handle<AccessorInfo> Accessors::FunctionPrototypeInfo(
      Isolate* isolate, PropertyAttributes attributes) {
  return MakeAccessor(isolate,
                      isolate->factory()->prototype_string(),
                      &FunctionPrototypeGetter,
                      &FunctionPrototypeSetter,
                      attributes);
}
738 739 740 741 742 743 744


//
// Accessors::FunctionLength
//


745
void Accessors::FunctionLengthGetter(
746
    v8::Local<v8::Name> name,
747 748
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
749
  HandleScope scope(isolate);
750 751
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
752 753
  Handle<Object> result;
  if (!JSFunction::GetLength(isolate, function).ToHandle(&result)) {
754
    result = handle(Smi::kZero, isolate);
755
    isolate->OptionalRescheduleException(false);
756
  }
757

758
  info.GetReturnValue().Set(Utils::ToLocal(result));
759 760
}

761 762
Handle<AccessorInfo> Accessors::FunctionLengthInfo(
      Isolate* isolate, PropertyAttributes attributes) {
763
  return MakeAccessor(isolate, isolate->factory()->length_string(),
764
                      &FunctionLengthGetter, &ReconfigureToDataProperty,
765 766
                      attributes);
}
767 768 769 770 771 772 773


//
// Accessors::FunctionName
//


774
void Accessors::FunctionNameGetter(
775
    v8::Local<v8::Name> name,
776 777 778
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
779 780
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
781
  Handle<Object> result = JSFunction::GetName(isolate, function);
782
  info.GetReturnValue().Set(Utils::ToLocal(result));
783 784
}

785 786
Handle<AccessorInfo> Accessors::FunctionNameInfo(
      Isolate* isolate, PropertyAttributes attributes) {
787
  return MakeAccessor(isolate, isolate->factory()->name_string(),
788
                      &FunctionNameGetter, &ReconfigureToDataProperty,
789 790
                      attributes);
}
791 792 793 794 795 796


//
// Accessors::FunctionArguments
//

797

798
static Handle<Object> ArgumentsForInlinedFunction(
799 800 801
    JavaScriptFrame* frame,
    Handle<JSFunction> inlined_function,
    int inlined_frame_index) {
802 803
  Isolate* isolate = inlined_function->GetIsolate();
  Factory* factory = isolate->factory();
jarin@chromium.org's avatar
jarin@chromium.org committed
804

805 806 807 808 809 810 811 812 813
  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();

814 815 816
  // Skip the function.
  iter++;

817 818 819 820
  // Skip the receiver.
  iter++;
  argument_count--;

821
  Handle<JSObject> arguments =
822 823 824 825
      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) {
826 827
    // If we materialize any object, we should deoptimize the frame because we
    // might alias an object that was eliminated by escape analysis.
828 829
    should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
    Handle<Object> value = iter->GetValue();
830
    array->set(i, *value);
831
    iter++;
832 833 834
  }
  arguments->set_elements(*array);

835
  if (should_deoptimize) {
836
    translated_values.StoreMaterializedValuesAndDeopt(frame);
837 838
  }

839
  // Return the freshly allocated arguments object.
840
  return arguments;
841 842
}

843

844 845 846
static int FindFunctionInFrame(JavaScriptFrame* frame,
                               Handle<JSFunction> function) {
  DisallowHeapAllocation no_allocation;
847 848 849 850
  List<FrameSummary> frames(2);
  frame->Summarize(&frames);
  for (int i = frames.length() - 1; i >= 0; i--) {
    if (*frames[i].AsJavaScript().function() == *function) return i;
851 852 853 854 855
  }
  return -1;
}


856 857
namespace {

858 859
Handle<Object> GetFunctionArguments(Isolate* isolate,
                                    Handle<JSFunction> function) {
860
  // Find the top invocation of the function by traversing frames.
861
  for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
862
    JavaScriptFrame* frame = it.frame();
863 864 865 866 867 868 869 870 871 872
    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);
    }
873

874
    // Find the frame that holds the actual arguments passed to the function.
875 876 877 878 879 880 881 882 883 884 885
    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.
886
    DCHECK(array->length() == length);
887 888 889 890 891 892 893 894 895 896
    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);
    }
897 898 899 900
    arguments->set_elements(*array);

    // Return the freshly allocated arguments object.
    return arguments;
901 902 903
  }

  // No frame corresponding to the given function found. Return null.
904 905 906
  return isolate->factory()->null_value();
}

907 908
}  // namespace

909

910 911 912 913 914
Handle<JSObject> Accessors::FunctionGetArguments(Handle<JSFunction> function) {
  Handle<Object> arguments =
      GetFunctionArguments(function->GetIsolate(), function);
  CHECK(arguments->IsJSObject());
  return Handle<JSObject>::cast(arguments);
915 916 917
}


918
void Accessors::FunctionArgumentsGetter(
919
    v8::Local<v8::Name> name,
920 921
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
922
  HandleScope scope(isolate);
923 924
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
925 926 927 928
  Handle<Object> result =
      function->shared()->native()
          ? Handle<Object>::cast(isolate->factory()->null_value())
          : GetFunctionArguments(isolate, function);
929
  info.GetReturnValue().Set(Utils::ToLocal(result));
930 931 932
}


933 934
Handle<AccessorInfo> Accessors::FunctionArgumentsInfo(
      Isolate* isolate, PropertyAttributes attributes) {
935 936
  return MakeAccessor(isolate, isolate->factory()->arguments_string(),
                      &FunctionArgumentsGetter, nullptr, attributes);
937
}
938 939 940 941 942 943 944


//
// Accessors::FunctionCaller
//


945 946 947 948 949 950
static inline bool AllowAccessToFunction(Context* current_context,
                                         JSFunction* function) {
  return current_context->HasSameSecurityTokenAs(function->context());
}


951 952
class FrameFunctionIterator {
 public:
953
  FrameFunctionIterator(Isolate* isolate, const DisallowHeapAllocation& promise)
954 955
      : isolate_(isolate), frame_iterator_(isolate), frames_(2), index_(0) {
    GetFrames();
956 957
  }
  JSFunction* next() {
958
    while (true) {
959 960
      if (frames_.length() == 0) return NULL;
      JSFunction* next_function = *frames_[index_].AsJavaScript().function();
961 962
      index_--;
      if (index_ < 0) {
963
        GetFrames();
964 965 966 967
      }
      // Skip functions from other origins.
      if (!AllowAccessToFunction(isolate_->context(), next_function)) continue;
      return next_function;
968 969 970 971 972 973 974 975 976 977 978 979 980 981
    }
  }

  // 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;
  }
982

983
 private:
984 985
  void GetFrames() {
    frames_.Rewind(0);
986 987
    if (frame_iterator_.done()) return;
    JavaScriptFrame* frame = frame_iterator_.frame();
988 989
    frame->Summarize(&frames_);
    DCHECK(frames_.length() > 0);
990
    frame_iterator_.Advance();
991
    index_ = frames_.length() - 1;
992
  }
993
  Isolate* isolate_;
994
  JavaScriptFrameIterator frame_iterator_;
995
  List<FrameSummary> frames_;
996 997 998 999
  int index_;
};


1000 1001
MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
                                   Handle<JSFunction> function) {
1002 1003
  DisallowHeapAllocation no_allocation;
  FrameFunctionIterator it(isolate, no_allocation);
1004 1005 1006
  if (function->shared()->native()) {
    return MaybeHandle<JSFunction>();
  }
1007 1008 1009
  // Find the function from the frames.
  if (!it.Find(*function)) {
    // No frame corresponding to the given function found. Return null.
1010
    return MaybeHandle<JSFunction>();
1011
  }
1012 1013 1014 1015
  // Find previously called non-toplevel function.
  JSFunction* caller;
  do {
    caller = it.next();
1016
    if (caller == NULL) return MaybeHandle<JSFunction>();
1017 1018
  } while (caller->shared()->is_toplevel());

1019
  // If caller is not user code and caller's caller is also not user code,
1020 1021
  // use that instead.
  JSFunction* potential_caller = caller;
1022 1023
  while (potential_caller != NULL &&
         !potential_caller->shared()->IsUserJavaScript()) {
1024 1025 1026
    caller = potential_caller;
    potential_caller = it.next();
  }
1027 1028 1029
  if (!caller->shared()->native() && potential_caller != NULL) {
    caller = potential_caller;
  }
1030
  // Censor if the caller is not a sloppy mode function.
1031 1032
  // Change from ES5, which used to throw, see:
  // https://bugs.ecmascript.org/show_bug.cgi?id=310
1033
  if (is_strict(caller->shared()->language_mode())) {
1034 1035
    return MaybeHandle<JSFunction>();
  }
1036 1037 1038 1039
  // Don't return caller from another security context.
  if (!AllowAccessToFunction(isolate->context(), caller)) {
    return MaybeHandle<JSFunction>();
  }
1040 1041 1042 1043 1044
  return Handle<JSFunction>(caller);
}


void Accessors::FunctionCallerGetter(
1045
    v8::Local<v8::Name> name,
1046 1047 1048
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
1049 1050
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
1051
  Handle<Object> result;
1052 1053 1054 1055 1056
  MaybeHandle<JSFunction> maybe_caller;
  maybe_caller = FindCaller(isolate, function);
  Handle<JSFunction> caller;
  if (maybe_caller.ToHandle(&caller)) {
    result = caller;
1057
  } else {
1058
    result = isolate->factory()->null_value();
1059
  }
1060 1061 1062
  info.GetReturnValue().Set(Utils::ToLocal(result));
}

1063

1064 1065
Handle<AccessorInfo> Accessors::FunctionCallerInfo(
      Isolate* isolate, PropertyAttributes attributes) {
1066 1067
  return MakeAccessor(isolate, isolate->factory()->caller_string(),
                      &FunctionCallerGetter, nullptr, attributes);
1068
}
1069 1070


1071 1072 1073 1074 1075 1076 1077
//
// 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());
1078 1079 1080
  RuntimeCallTimerScope timer(
      isolate,
      &RuntimeCallStats::AccessorNameGetterCallback_BoundFunctionLength);
1081 1082 1083 1084 1085 1086 1087 1088
  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)) {
1089
    target_length = handle(Smi::kZero, isolate);
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
    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(),
1104 1105
                      &BoundFunctionLengthGetter, &ReconfigureToDataProperty,
                      attributes);
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());
1115 1116
  RuntimeCallTimerScope timer(
      isolate, &RuntimeCallStats::AccessorNameGetterCallback_BoundFunctionName);
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
  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(),
1131 1132
                      &BoundFunctionNameGetter, &ReconfigureToDataProperty,
                      attributes);
1133 1134
}

jgruber's avatar
jgruber committed
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 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
//
// 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;
1190
  if (!ErrorUtils::FormatStackTrace(isolate, holder, stack_trace)
jgruber's avatar
jgruber committed
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
           .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.
1205 1206
  Handle<Object> receiver =
      Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
jgruber's avatar
jgruber committed
1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
  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);
}

1227 1228 1229
void Accessors::ErrorStackSetter(
    v8::Local<v8::Name> name, v8::Local<v8::Value> val,
    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
jgruber's avatar
jgruber committed
1230 1231
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
1232 1233
  Handle<JSObject> obj = Handle<JSObject>::cast(
      Utils::OpenHandle(*v8::Local<v8::Value>(info.This())));
jgruber's avatar
jgruber committed
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250

  // 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;
}
1251

1252 1253
}  // namespace internal
}  // namespace v8