accessors.cc 31.8 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-inl.h"
8
#include "src/contexts.h"
9
#include "src/counters.h"
10 11 12
#include "src/deoptimizer.h"
#include "src/execution.h"
#include "src/frames-inl.h"
13
#include "src/heap/factory.h"
14
#include "src/isolate-inl.h"
15
#include "src/messages.h"
16
#include "src/objects/api-callbacks.h"
17
#include "src/objects/js-array-inl.h"
18
#include "src/objects/module-inl.h"
19
#include "src/property-details.h"
20
#include "src/prototype.h"
21

22 23
namespace v8 {
namespace internal {
24

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

52
static V8_INLINE bool CheckForName(Isolate* isolate, Handle<Name> name,
53 54 55
                                   Handle<String> property_name, int offset,
                                   FieldIndex::Encoding encoding,
                                   FieldIndex* index) {
56
  if (Name::Equals(isolate, name, property_name)) {
57
    *index = FieldIndex::ForInObjectOffset(offset, encoding);
58 59 60 61 62 63
    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 67
bool Accessors::IsJSObjectFieldAccessor(Isolate* isolate, Handle<Map> map,
                                        Handle<Name> name, FieldIndex* index) {
68 69
  switch (map->instance_type()) {
    case JS_ARRAY_TYPE:
70
      return CheckForName(isolate, name, isolate->factory()->length_string(),
71
                          JSArray::kLengthOffset, FieldIndex::kTagged, index);
72 73
    default:
      if (map->instance_type() < FIRST_NONSTRING_TYPE) {
74
        return CheckForName(isolate, name, isolate->factory()->length_string(),
75
                            String::kLengthOffset, FieldIndex::kWord32, index);
76 77 78 79 80 81
      }

      return false;
  }
}

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

101

102 103 104
//
// Accessors::ReconfigureToDataProperty
//
105 106
void Accessors::ReconfigureToDataProperty(
    v8::Local<v8::Name> key, v8::Local<v8::Value> val,
107
    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
108
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
109
  RuntimeCallTimerScope stats_scope(
110
      isolate, RuntimeCallCounterId::kReconfigureToDataProperty);
111
  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 =
      Accessors::ReplaceAccessorWithDataProperty(receiver, holder, name, value);
119 120 121 122 123
  if (result.is_null()) {
    isolate->OptionalRescheduleException(false);
  } else {
    info.GetReturnValue().Set(true);
  }
124
}
125

126

127 128 129 130 131 132 133 134 135 136 137 138 139 140
//
// 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)));
}

141
Handle<AccessorInfo> Accessors::MakeArgumentsIteratorInfo(Isolate* isolate) {
142
  Handle<Name> name = isolate->factory()->iterator_symbol();
143
  return MakeAccessor(isolate, name, &ArgumentsIteratorGetter, nullptr);
144 145 146
}


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


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

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

173 174
  DCHECK(Utils::OpenHandle(*name)->SameValue(
      ReadOnlyRoots(isolate).length_string()));
175

176
  Handle<JSReceiver> object = Utils::OpenHandle(*info.Holder());
177 178 179
  Handle<JSArray> array = Handle<JSArray>::cast(object);
  Handle<Object> length_obj = Utils::OpenHandle(*val);

180 181
  bool was_readonly = JSArray::HasReadOnlyLength(array);

182
  uint32_t length = 0;
183 184 185
  if (!JSArray::AnythingToArrayLength(isolate, length_obj, &length)) {
    isolate->OptionalRescheduleException(false);
    return;
186
  }
187

188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
  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;
  }

206
  JSArray::SetLength(array, length);
207

208 209 210 211 212
  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()) {
213 214 215 216 217
      Factory* factory = isolate->factory();
      isolate->Throw(*factory->NewTypeError(
          MessageTemplate::kStrictDeleteProperty,
          factory->NewNumberFromUint(actual_new_len - 1), array));
      isolate->OptionalRescheduleException(false);
218 219
    } else {
      info.GetReturnValue().Set(false);
220
    }
221 222
  } else {
    info.GetReturnValue().Set(true);
223
  }
224 225
}

226
Handle<AccessorInfo> Accessors::MakeArrayLengthInfo(Isolate* isolate) {
227 228
  return MakeAccessor(isolate, isolate->factory()->length_string(),
                      &ArrayLengthGetter, &ArrayLengthSetter);
229 230 231 232 233 234 235 236 237 238
}

//
// 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);
239
  JSModuleNamespace holder =
240 241
      JSModuleNamespace::cast(*Utils::OpenHandle(*info.Holder()));
  Handle<Object> result;
242 243
  if (!holder
           ->GetExport(isolate, Handle<String>::cast(Utils::OpenHandle(*name)))
244 245 246 247 248 249 250 251 252
           .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
Handle<AccessorInfo> Accessors::MakeModuleNamespaceEntryInfo(
    Isolate* isolate, Handle<String> name) {
272
  return MakeAccessor(isolate, name, &ModuleNamespaceEntryGetter,
273
                      &ModuleNamespaceEntrySetter);
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,
                              RuntimeCallCounterId::kStringLengthGetter);
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
Handle<AccessorInfo> Accessors::MakeStringLengthInfo(Isolate* isolate) {
306
  return MakeAccessor(isolate, isolate->factory()->length_string(),
307
                      &StringLengthGetter, nullptr);
308
}
309 310 311 312 313

//
// Accessors::FunctionPrototype
//

314 315 316 317 318 319 320 321 322
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);
}

323
void Accessors::FunctionPrototypeGetter(
324
    v8::Local<v8::Name> name,
325 326
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
327
  RuntimeCallTimerScope timer(isolate,
328
                              RuntimeCallCounterId::kFunctionPrototypeGetter);
329
  HandleScope scope(isolate);
330 331
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
332
  DCHECK(function->has_prototype_property());
333
  Handle<Object> result = GetFunctionPrototype(isolate, function);
334
  info.GetReturnValue().Set(Utils::ToLocal(result));
335 336
}

337
void Accessors::FunctionPrototypeSetter(
338 339
    v8::Local<v8::Name> name, v8::Local<v8::Value> val,
    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
340
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
341
  RuntimeCallTimerScope timer(isolate,
342
                              RuntimeCallCounterId::kFunctionPrototypeSetter);
343 344
  HandleScope scope(isolate);
  Handle<Object> value = Utils::OpenHandle(*val);
345 346
  Handle<JSFunction> object =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
347
  DCHECK(object->has_prototype_property());
348 349
  JSFunction::SetPrototype(object, value);
  info.GetReturnValue().Set(true);
350 351
}

352
Handle<AccessorInfo> Accessors::MakeFunctionPrototypeInfo(Isolate* isolate) {
353 354
  return MakeAccessor(isolate, isolate->factory()->prototype_string(),
                      &FunctionPrototypeGetter, &FunctionPrototypeSetter);
355
}
356 357 358 359 360 361 362


//
// Accessors::FunctionLength
//


363
void Accessors::FunctionLengthGetter(
364
    v8::Local<v8::Name> name,
365 366
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
367 368
  RuntimeCallTimerScope timer(isolate,
                              RuntimeCallCounterId::kFunctionLengthGetter);
369
  HandleScope scope(isolate);
370 371
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
372 373
  int length = 0;
  if (!JSFunction::GetLength(isolate, function).To(&length)) {
374
    isolate->OptionalRescheduleException(false);
375
  }
376
  Handle<Object> result(Smi::FromInt(length), isolate);
377
  info.GetReturnValue().Set(Utils::ToLocal(result));
378 379
}

380
Handle<AccessorInfo> Accessors::MakeFunctionLengthInfo(Isolate* isolate) {
381
  return MakeAccessor(isolate, isolate->factory()->length_string(),
382
                      &FunctionLengthGetter, &ReconfigureToDataProperty);
383
}
384 385 386 387 388 389 390


//
// Accessors::FunctionName
//


391
void Accessors::FunctionNameGetter(
392
    v8::Local<v8::Name> name,
393 394 395
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
396 397
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
398
  Handle<Object> result = JSFunction::GetName(isolate, function);
399
  info.GetReturnValue().Set(Utils::ToLocal(result));
400 401
}

402
Handle<AccessorInfo> Accessors::MakeFunctionNameInfo(Isolate* isolate) {
403
  return MakeAccessor(isolate, isolate->factory()->name_string(),
404
                      &FunctionNameGetter, &ReconfigureToDataProperty);
405
}
406 407 408 409 410 411


//
// Accessors::FunctionArguments
//

412
namespace {
413

414 415 416
Handle<JSObject> ArgumentsForInlinedFunction(JavaScriptFrame* frame,
                                             int inlined_frame_index) {
  Isolate* isolate = frame->isolate();
417
  Factory* factory = isolate->factory();
jarin@chromium.org's avatar
jarin@chromium.org committed
418

419
  TranslatedState translated_values(frame);
420
  translated_values.Prepare(frame->fp());
421 422 423 424 425 426 427

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

428 429 430
  // Materialize the function.
  bool should_deoptimize = iter->IsMaterializedObject();
  Handle<JSFunction> function = Handle<JSFunction>::cast(iter->GetValue());
431 432
  iter++;

433 434 435 436
  // Skip the receiver.
  iter++;
  argument_count--;

437
  Handle<JSObject> arguments =
438
      factory->NewArgumentsObject(function, argument_count);
439 440
  Handle<FixedArray> array = factory->NewFixedArray(argument_count);
  for (int i = 0; i < argument_count; ++i) {
441 442
    // If we materialize any object, we should deoptimize the frame because we
    // might alias an object that was eliminated by escape analysis.
443 444
    should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
    Handle<Object> value = iter->GetValue();
445
    array->set(i, *value);
446
    iter++;
447 448 449
  }
  arguments->set_elements(*array);

450
  if (should_deoptimize) {
451
    translated_values.StoreMaterializedValuesAndDeopt(frame);
452 453
  }

454
  // Return the freshly allocated arguments object.
455
  return arguments;
456 457
}

458
int FindFunctionInFrame(JavaScriptFrame* frame, Handle<JSFunction> function) {
459
  std::vector<FrameSummary> frames;
460
  frame->Summarize(&frames);
461 462 463 464
  for (size_t i = frames.size(); i != 0; i--) {
    if (*frames[i - 1].AsJavaScript().function() == *function) {
      return static_cast<int>(i) - 1;
    }
465 466 467 468
  }
  return -1;
}

469 470 471 472
Handle<JSObject> GetFrameArguments(Isolate* isolate,
                                   JavaScriptFrameIterator* it,
                                   int function_index) {
  JavaScriptFrame* frame = it->frame();
473

474 475 476 477 478 479 480
  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_index);
  }
481

482 483 484 485 486 487
  // Find the frame that holds the actual arguments passed to the function.
  if (it->frame()->has_adapted_arguments()) {
    it->AdvanceOneFrame();
    DCHECK(it->frame()->is_arguments_adaptor());
  }
  frame = it->frame();
488

489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
  // Get the number of arguments and construct an arguments object
  // mirror for the right frame and the underlying function.
  const int length = frame->ComputeParametersCount();
  Handle<JSFunction> function(frame->function(), isolate);
  Handle<JSObject> arguments =
      isolate->factory()->NewArgumentsObject(function, length);
  Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);

  // Copy the parameters to the arguments object.
  DCHECK(array->length() == length);
  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()));
505
      value = ReadOnlyRoots(isolate).undefined_value();
506
    }
507
    array->set(i, value);
508
  }
509
  arguments->set_elements(*array);
510

511 512
  // Return the freshly allocated arguments object.
  return arguments;
513 514
}

515 516
}  // namespace

517 518 519 520 521 522 523 524 525 526 527 528
Handle<JSObject> Accessors::FunctionGetArguments(JavaScriptFrame* frame,
                                                 int inlined_jsframe_index) {
  Isolate* isolate = frame->isolate();
  Address requested_frame_fp = frame->fp();
  // Forward a frame iterator to the requested frame. This is needed because we
  // potentially need for advance it to the arguments adaptor frame later.
  for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
    if (it.frame()->fp() != requested_frame_fp) continue;
    return GetFrameArguments(isolate, &it, inlined_jsframe_index);
  }
  UNREACHABLE();  // Requested frame not found.
  return Handle<JSObject>();
529 530 531
}


532
void Accessors::FunctionArgumentsGetter(
533
    v8::Local<v8::Name> name,
534 535
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
536
  HandleScope scope(isolate);
537 538
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
539 540 541 542 543 544 545 546 547 548 549 550
  Handle<Object> result = isolate->factory()->null_value();
  if (!function->shared()->native()) {
    // Find the top invocation of the function by traversing frames.
    for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
      JavaScriptFrame* frame = it.frame();
      int function_index = FindFunctionInFrame(frame, function);
      if (function_index >= 0) {
        result = GetFrameArguments(isolate, &it, function_index);
        break;
      }
    }
  }
551
  info.GetReturnValue().Set(Utils::ToLocal(result));
552 553
}

554
Handle<AccessorInfo> Accessors::MakeFunctionArgumentsInfo(Isolate* isolate) {
555
  return MakeAccessor(isolate, isolate->factory()->arguments_string(),
556
                      &FunctionArgumentsGetter, nullptr);
557
}
558 559 560 561 562 563


//
// Accessors::FunctionCaller
//

564
static inline bool AllowAccessToFunction(Context current_context,
565
                                         JSFunction function) {
566 567 568
  return current_context->HasSameSecurityTokenAs(function->context());
}

569 570
class FrameFunctionIterator {
 public:
571
  explicit FrameFunctionIterator(Isolate* isolate)
572
      : isolate_(isolate), frame_iterator_(isolate), inlined_frame_index_(-1) {
573
    GetFrames();
574
  }
575 576

  // Iterate through functions until the first occurrence of 'function'.
577
  // Returns true if one is found, and false if the iterator ends before.
578 579
  bool Find(Handle<JSFunction> function) {
    do {
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
      if (!next().ToHandle(&function_)) return false;
    } while (!function_.is_identical_to(function));
    return true;
  }

  // Iterate through functions until the next non-toplevel one is found.
  // Returns true if one is found, and false if the iterator ends before.
  bool FindNextNonTopLevel() {
    do {
      if (!next().ToHandle(&function_)) return false;
    } while (function_->shared()->is_toplevel());
    return true;
  }

  // Iterate through function until the first native or user-provided function
  // is found. Functions not defined in user-provided scripts are not visible
  // unless directly exposed, in which case the native flag is set on them.
  // Returns true if one is found, and false if the iterator ends before.
  bool FindFirstNativeOrUserJavaScript() {
    while (!function_->shared()->native() &&
           !function_->shared()->IsUserJavaScript()) {
      if (!next().ToHandle(&function_)) return false;
    }
603 604 605
    return true;
  }

606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
  // In case of inlined frames the function could have been materialized from
  // deoptimization information. If that is the case we need to make sure that
  // subsequent call will see the same function, since we are about to hand out
  // the value to JavaScript. Make sure to store the materialized value and
  // trigger a deoptimization of the underlying frame.
  Handle<JSFunction> MaterializeFunction() {
    if (inlined_frame_index_ == 0) return function_;

    JavaScriptFrame* frame = frame_iterator_.frame();
    TranslatedState translated_values(frame);
    translated_values.Prepare(frame->fp());

    TranslatedFrame* translated_frame =
        translated_values.GetFrameFromJSFrameIndex(inlined_frame_index_);
    TranslatedFrame::iterator iter = translated_frame->begin();

    // First value is the function.
    bool should_deoptimize = iter->IsMaterializedObject();
    Handle<Object> value = iter->GetValue();
    if (should_deoptimize) {
      translated_values.StoreMaterializedValuesAndDeopt(frame);
    }

    return Handle<JSFunction>::cast(value);
  }

632
 private:
633 634
  MaybeHandle<JSFunction> next() {
    while (true) {
635
      if (inlined_frame_index_ <= 0) {
636 637 638
        if (!frame_iterator_.done()) {
          frame_iterator_.Advance();
          frames_.clear();
639
          inlined_frame_index_ = -1;
640 641 642 643
          GetFrames();
        }
        if (inlined_frame_index_ == -1) return MaybeHandle<JSFunction>();
      }
644 645

      --inlined_frame_index_;
646 647 648 649 650 651 652
      Handle<JSFunction> next_function =
          frames_[inlined_frame_index_].AsJavaScript().function();
      // Skip functions from other origins.
      if (!AllowAccessToFunction(isolate_->context(), *next_function)) continue;
      return next_function;
    }
  }
653
  void GetFrames() {
654
    DCHECK_EQ(-1, inlined_frame_index_);
655 656
    if (frame_iterator_.done()) return;
    JavaScriptFrame* frame = frame_iterator_.frame();
657
    frame->Summarize(&frames_);
658 659
    inlined_frame_index_ = static_cast<int>(frames_.size());
    DCHECK_LT(0, inlined_frame_index_);
660
  }
661
  Isolate* isolate_;
662
  Handle<JSFunction> function_;
663
  JavaScriptFrameIterator frame_iterator_;
664
  std::vector<FrameSummary> frames_;
665
  int inlined_frame_index_;
666 667 668
};


669 670
MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
                                   Handle<JSFunction> function) {
671
  FrameFunctionIterator it(isolate);
672 673 674
  if (function->shared()->native()) {
    return MaybeHandle<JSFunction>();
  }
675 676
  // Find the function from the frames. Return null in case no frame
  // corresponding to the given function was found.
677
  if (!it.Find(function)) {
678
    return MaybeHandle<JSFunction>();
679
  }
680
  // Find previously called non-toplevel function.
681 682
  if (!it.FindNextNonTopLevel()) {
    return MaybeHandle<JSFunction>();
683
  }
684 685 686 687
  // Find the first user-land JavaScript function (or the entry point into
  // native JavaScript builtins in case such a builtin was the caller).
  if (!it.FindFirstNativeOrUserJavaScript()) {
    return MaybeHandle<JSFunction>();
688
  }
689 690 691 692 693 694 695

  // Materialize the function that the iterator is currently sitting on. Note
  // that this might trigger deoptimization in case the function was actually
  // materialized. Identity of the function must be preserved because we are
  // going to return it to JavaScript after this point.
  Handle<JSFunction> caller = it.MaterializeFunction();

696
  // Censor if the caller is not a sloppy mode function.
697 698
  // Change from ES5, which used to throw, see:
  // https://bugs.ecmascript.org/show_bug.cgi?id=310
699
  if (is_strict(caller->shared()->language_mode())) {
700 701
    return MaybeHandle<JSFunction>();
  }
702
  // Don't return caller from another security context.
703
  if (!AllowAccessToFunction(isolate->context(), *caller)) {
704 705
    return MaybeHandle<JSFunction>();
  }
706
  return caller;
707 708 709 710
}


void Accessors::FunctionCallerGetter(
711
    v8::Local<v8::Name> name,
712 713 714
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
715 716
  Handle<JSFunction> function =
      Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
717
  Handle<Object> result;
718 719 720 721 722
  MaybeHandle<JSFunction> maybe_caller;
  maybe_caller = FindCaller(isolate, function);
  Handle<JSFunction> caller;
  if (maybe_caller.ToHandle(&caller)) {
    result = caller;
723
  } else {
724
    result = isolate->factory()->null_value();
725
  }
726 727 728
  info.GetReturnValue().Set(Utils::ToLocal(result));
}

729
Handle<AccessorInfo> Accessors::MakeFunctionCallerInfo(Isolate* isolate) {
730
  return MakeAccessor(isolate, isolate->factory()->caller_string(),
731
                      &FunctionCallerGetter, nullptr);
732
}
733 734


735 736 737 738 739 740 741
//
// 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());
742
  RuntimeCallTimerScope timer(isolate,
743
                              RuntimeCallCounterId::kBoundFunctionLengthGetter);
744 745 746 747
  HandleScope scope(isolate);
  Handle<JSBoundFunction> function =
      Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));

748 749
  int length = 0;
  if (!JSBoundFunction::GetLength(isolate, function).To(&length)) {
750 751 752 753 754 755 756
    isolate->OptionalRescheduleException(false);
    return;
  }
  Handle<Object> result(Smi::FromInt(length), isolate);
  info.GetReturnValue().Set(Utils::ToLocal(result));
}

757
Handle<AccessorInfo> Accessors::MakeBoundFunctionLengthInfo(Isolate* isolate) {
758
  return MakeAccessor(isolate, isolate->factory()->length_string(),
759
                      &BoundFunctionLengthGetter, &ReconfigureToDataProperty);
760 761 762 763 764 765 766 767 768
}

//
// 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());
769
  RuntimeCallTimerScope timer(isolate,
770
                              RuntimeCallCounterId::kBoundFunctionNameGetter);
771 772 773 774 775 776 777 778 779 780 781
  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));
}

782
Handle<AccessorInfo> Accessors::MakeBoundFunctionNameInfo(Isolate* isolate) {
783
  return MakeAccessor(isolate, isolate->factory()->name_string(),
784
                      &BoundFunctionNameGetter, &ReconfigureToDataProperty);
785 786
}

jgruber's avatar
jgruber committed
787 788 789 790 791 792 793 794 795 796
//
// Accessors::ErrorStack
//

namespace {

MaybeHandle<JSReceiver> ClearInternalStackTrace(Isolate* isolate,
                                                Handle<JSObject> error) {
  RETURN_ON_EXCEPTION(
      isolate,
797
      Object::SetProperty(
798 799
          isolate, error, isolate->factory()->stack_trace_symbol(),
          isolate->factory()->undefined_value(), LanguageMode::kStrict),
jgruber's avatar
jgruber committed
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
      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 =
831
      JSObject::GetProperty(isolate, holder, stack_trace_symbol);
jgruber's avatar
jgruber committed
832 833 834 835 836 837 838 839 840 841 842
  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;
843
  if (!ErrorUtils::FormatStackTrace(isolate, holder, stack_trace)
jgruber's avatar
jgruber committed
844 845 846 847 848 849 850 851 852 853 854 855 856 857
           .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.
858 859
  Handle<Object> receiver =
      Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
jgruber's avatar
jgruber committed
860 861
  Handle<Name> name = Utils::OpenHandle(*key);
  if (IsAccessor(receiver, name, holder)) {
862 863
    result = Accessors::ReplaceAccessorWithDataProperty(receiver, holder, name,
                                                        formatted_stack_trace);
jgruber's avatar
jgruber committed
864 865 866 867 868 869
    if (result.is_null()) {
      isolate->OptionalRescheduleException(false);
      return;
    }
  } else {
    // The stack property has been modified in the meantime.
870 871
    if (!JSObject::GetProperty(isolate, holder, name)
             .ToHandle(&formatted_stack_trace)) {
jgruber's avatar
jgruber committed
872 873 874 875 876 877 878 879 880
      isolate->OptionalRescheduleException(false);
      return;
    }
  }

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

881 882 883
void Accessors::ErrorStackSetter(
    v8::Local<v8::Name> name, v8::Local<v8::Value> val,
    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
jgruber's avatar
jgruber committed
884 885
  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
  HandleScope scope(isolate);
886 887
  Handle<JSObject> obj = Handle<JSObject>::cast(
      Utils::OpenHandle(*v8::Local<v8::Value>(info.This())));
jgruber's avatar
jgruber committed
888 889 890 891 892 893 894 895 896 897

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

898
Handle<AccessorInfo> Accessors::MakeErrorStackInfo(Isolate* isolate) {
899 900
  return MakeAccessor(isolate, isolate->factory()->stack_string(),
                      &ErrorStackGetter, &ErrorStackSetter);
jgruber's avatar
jgruber committed
901
}
902

903 904
}  // namespace internal
}  // namespace v8