Home | History | Annotate | Download | only in src
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // 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/deoptimizer.h"
     10 #include "src/execution.h"
     11 #include "src/frames-inl.h"
     12 #include "src/heap/factory.h"
     13 #include "src/isolate-inl.h"
     14 #include "src/messages.h"
     15 #include "src/objects/api-callbacks.h"
     16 #include "src/objects/js-array-inl.h"
     17 #include "src/objects/module-inl.h"
     18 #include "src/property-details.h"
     19 #include "src/prototype.h"
     20 
     21 namespace v8 {
     22 namespace internal {
     23 
     24 Handle<AccessorInfo> Accessors::MakeAccessor(
     25     Isolate* isolate, Handle<Name> name, AccessorNameGetterCallback getter,
     26     AccessorNameBooleanSetterCallback setter) {
     27   Factory* factory = isolate->factory();
     28   Handle<AccessorInfo> info = factory->NewAccessorInfo();
     29   info->set_all_can_read(false);
     30   info->set_all_can_write(false);
     31   info->set_is_special_data_property(true);
     32   info->set_is_sloppy(false);
     33   info->set_replace_on_access(false);
     34   info->set_has_no_side_effect(false);
     35   name = factory->InternalizeName(name);
     36   info->set_name(*name);
     37   Handle<Object> get = v8::FromCData(isolate, getter);
     38   if (setter == nullptr) setter = &ReconfigureToDataProperty;
     39   Handle<Object> set = v8::FromCData(isolate, setter);
     40   info->set_getter(*get);
     41   info->set_setter(*set);
     42   Address redirected = info->redirected_getter();
     43   if (redirected != kNullAddress) {
     44     Handle<Object> js_get = v8::FromCData(isolate, redirected);
     45     info->set_js_getter(*js_get);
     46   }
     47   return info;
     48 }
     49 
     50 static V8_INLINE bool CheckForName(Isolate* isolate, Handle<Name> name,
     51                                    Handle<String> property_name, int offset,
     52                                    FieldIndex::Encoding encoding,
     53                                    FieldIndex* index) {
     54   if (Name::Equals(isolate, name, property_name)) {
     55     *index = FieldIndex::ForInObjectOffset(offset, encoding);
     56     return true;
     57   }
     58   return false;
     59 }
     60 
     61 
     62 // Returns true for properties that are accessors to object fields.
     63 // If true, *object_offset contains offset of object field.
     64 bool Accessors::IsJSObjectFieldAccessor(Isolate* isolate, Handle<Map> map,
     65                                         Handle<Name> name, FieldIndex* index) {
     66   switch (map->instance_type()) {
     67     case JS_ARRAY_TYPE:
     68       return CheckForName(isolate, name, isolate->factory()->length_string(),
     69                           JSArray::kLengthOffset, FieldIndex::kTagged, index);
     70     default:
     71       if (map->instance_type() < FIRST_NONSTRING_TYPE) {
     72         return CheckForName(isolate, name, isolate->factory()->length_string(),
     73                             String::kLengthOffset, FieldIndex::kTagged, index);
     74       }
     75 
     76       return false;
     77   }
     78 }
     79 
     80 V8_WARN_UNUSED_RESULT MaybeHandle<Object>
     81 Accessors::ReplaceAccessorWithDataProperty(Handle<Object> receiver,
     82                                            Handle<JSObject> holder,
     83                                            Handle<Name> name,
     84                                            Handle<Object> value) {
     85   LookupIterator it(receiver, name, holder,
     86                     LookupIterator::OWN_SKIP_INTERCEPTOR);
     87   // Skip any access checks we might hit. This accessor should never hit in a
     88   // situation where the caller does not have access.
     89   if (it.state() == LookupIterator::ACCESS_CHECK) {
     90     CHECK(it.HasAccess());
     91     it.Next();
     92   }
     93   DCHECK(holder.is_identical_to(it.GetHolder<JSObject>()));
     94   CHECK_EQ(LookupIterator::ACCESSOR, it.state());
     95   it.ReconfigureDataProperty(value, it.property_attributes());
     96   return value;
     97 }
     98 
     99 
    100 //
    101 // Accessors::ReconfigureToDataProperty
    102 //
    103 void Accessors::ReconfigureToDataProperty(
    104     v8::Local<v8::Name> key, v8::Local<v8::Value> val,
    105     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
    106   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    107   RuntimeCallTimerScope stats_scope(
    108       isolate, RuntimeCallCounterId::kReconfigureToDataProperty);
    109   HandleScope scope(isolate);
    110   Handle<Object> receiver = Utils::OpenHandle(*info.This());
    111   Handle<JSObject> holder =
    112       Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
    113   Handle<Name> name = Utils::OpenHandle(*key);
    114   Handle<Object> value = Utils::OpenHandle(*val);
    115   MaybeHandle<Object> result =
    116       Accessors::ReplaceAccessorWithDataProperty(receiver, holder, name, value);
    117   if (result.is_null()) {
    118     isolate->OptionalRescheduleException(false);
    119   } else {
    120     info.GetReturnValue().Set(true);
    121   }
    122 }
    123 
    124 
    125 //
    126 // Accessors::ArgumentsIterator
    127 //
    128 
    129 
    130 void Accessors::ArgumentsIteratorGetter(
    131     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    132   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    133   DisallowHeapAllocation no_allocation;
    134   HandleScope scope(isolate);
    135   Object* result = isolate->native_context()->array_values_iterator();
    136   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
    137 }
    138 
    139 Handle<AccessorInfo> Accessors::MakeArgumentsIteratorInfo(Isolate* isolate) {
    140   Handle<Name> name = isolate->factory()->iterator_symbol();
    141   return MakeAccessor(isolate, name, &ArgumentsIteratorGetter, nullptr);
    142 }
    143 
    144 
    145 //
    146 // Accessors::ArrayLength
    147 //
    148 
    149 
    150 void Accessors::ArrayLengthGetter(
    151     v8::Local<v8::Name> name,
    152     const v8::PropertyCallbackInfo<v8::Value>& info) {
    153   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    154   RuntimeCallTimerScope timer(isolate,
    155                               RuntimeCallCounterId::kArrayLengthGetter);
    156   DisallowHeapAllocation no_allocation;
    157   HandleScope scope(isolate);
    158   JSArray* holder = JSArray::cast(*Utils::OpenHandle(*info.Holder()));
    159   Object* result = holder->length();
    160   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
    161 }
    162 
    163 void Accessors::ArrayLengthSetter(
    164     v8::Local<v8::Name> name, v8::Local<v8::Value> val,
    165     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
    166   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    167   RuntimeCallTimerScope timer(isolate,
    168                               RuntimeCallCounterId::kArrayLengthSetter);
    169   HandleScope scope(isolate);
    170 
    171   DCHECK(Utils::OpenHandle(*name)->SameValue(
    172       ReadOnlyRoots(isolate).length_string()));
    173 
    174   Handle<JSReceiver> object = Utils::OpenHandle(*info.Holder());
    175   Handle<JSArray> array = Handle<JSArray>::cast(object);
    176   Handle<Object> length_obj = Utils::OpenHandle(*val);
    177 
    178   bool was_readonly = JSArray::HasReadOnlyLength(array);
    179 
    180   uint32_t length = 0;
    181   if (!JSArray::AnythingToArrayLength(isolate, length_obj, &length)) {
    182     isolate->OptionalRescheduleException(false);
    183     return;
    184   }
    185 
    186   if (!was_readonly && V8_UNLIKELY(JSArray::HasReadOnlyLength(array)) &&
    187       length != array->length()->Number()) {
    188     // AnythingToArrayLength() may have called setter re-entrantly and modified
    189     // its property descriptor. Don't perform this check if "length" was
    190     // previously readonly, as this may have been called during
    191     // DefineOwnPropertyIgnoreAttributes().
    192     if (info.ShouldThrowOnError()) {
    193       Factory* factory = isolate->factory();
    194       isolate->Throw(*factory->NewTypeError(
    195           MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
    196           i::Object::TypeOf(isolate, object), object));
    197       isolate->OptionalRescheduleException(false);
    198     } else {
    199       info.GetReturnValue().Set(false);
    200     }
    201     return;
    202   }
    203 
    204   JSArray::SetLength(array, length);
    205 
    206   uint32_t actual_new_len = 0;
    207   CHECK(array->length()->ToArrayLength(&actual_new_len));
    208   // Fail if there were non-deletable elements.
    209   if (actual_new_len != length) {
    210     if (info.ShouldThrowOnError()) {
    211       Factory* factory = isolate->factory();
    212       isolate->Throw(*factory->NewTypeError(
    213           MessageTemplate::kStrictDeleteProperty,
    214           factory->NewNumberFromUint(actual_new_len - 1), array));
    215       isolate->OptionalRescheduleException(false);
    216     } else {
    217       info.GetReturnValue().Set(false);
    218     }
    219   } else {
    220     info.GetReturnValue().Set(true);
    221   }
    222 }
    223 
    224 Handle<AccessorInfo> Accessors::MakeArrayLengthInfo(Isolate* isolate) {
    225   return MakeAccessor(isolate, isolate->factory()->length_string(),
    226                       &ArrayLengthGetter, &ArrayLengthSetter);
    227 }
    228 
    229 //
    230 // Accessors::ModuleNamespaceEntry
    231 //
    232 
    233 void Accessors::ModuleNamespaceEntryGetter(
    234     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    235   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    236   HandleScope scope(isolate);
    237   JSModuleNamespace* holder =
    238       JSModuleNamespace::cast(*Utils::OpenHandle(*info.Holder()));
    239   Handle<Object> result;
    240   if (!holder
    241            ->GetExport(isolate, Handle<String>::cast(Utils::OpenHandle(*name)))
    242            .ToHandle(&result)) {
    243     isolate->OptionalRescheduleException(false);
    244   } else {
    245     info.GetReturnValue().Set(Utils::ToLocal(result));
    246   }
    247 }
    248 
    249 void Accessors::ModuleNamespaceEntrySetter(
    250     v8::Local<v8::Name> name, v8::Local<v8::Value> val,
    251     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
    252   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    253   HandleScope scope(isolate);
    254   Factory* factory = isolate->factory();
    255   Handle<JSModuleNamespace> holder =
    256       Handle<JSModuleNamespace>::cast(Utils::OpenHandle(*info.Holder()));
    257 
    258   if (info.ShouldThrowOnError()) {
    259     isolate->Throw(*factory->NewTypeError(
    260         MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
    261         i::Object::TypeOf(isolate, holder), holder));
    262     isolate->OptionalRescheduleException(false);
    263   } else {
    264     info.GetReturnValue().Set(false);
    265   }
    266 }
    267 
    268 Handle<AccessorInfo> Accessors::MakeModuleNamespaceEntryInfo(
    269     Isolate* isolate, Handle<String> name) {
    270   return MakeAccessor(isolate, name, &ModuleNamespaceEntryGetter,
    271                       &ModuleNamespaceEntrySetter);
    272 }
    273 
    274 
    275 //
    276 // Accessors::StringLength
    277 //
    278 
    279 void Accessors::StringLengthGetter(
    280     v8::Local<v8::Name> name,
    281     const v8::PropertyCallbackInfo<v8::Value>& info) {
    282   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    283   RuntimeCallTimerScope timer(isolate,
    284                               RuntimeCallCounterId::kStringLengthGetter);
    285   DisallowHeapAllocation no_allocation;
    286   HandleScope scope(isolate);
    287 
    288   // We have a slight impedance mismatch between the external API and the way we
    289   // use callbacks internally: Externally, callbacks can only be used with
    290   // v8::Object, but internally we have callbacks on entities which are higher
    291   // in the hierarchy, in this case for String values.
    292 
    293   Object* value = *Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
    294   if (!value->IsString()) {
    295     // Not a string value. That means that we either got a String wrapper or
    296     // a Value with a String wrapper in its prototype chain.
    297     value = JSValue::cast(*Utils::OpenHandle(*info.Holder()))->value();
    298   }
    299   Object* result = Smi::FromInt(String::cast(value)->length());
    300   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
    301 }
    302 
    303 Handle<AccessorInfo> Accessors::MakeStringLengthInfo(Isolate* isolate) {
    304   return MakeAccessor(isolate, isolate->factory()->length_string(),
    305                       &StringLengthGetter, nullptr);
    306 }
    307 
    308 //
    309 // Accessors::FunctionPrototype
    310 //
    311 
    312 static Handle<Object> GetFunctionPrototype(Isolate* isolate,
    313                                            Handle<JSFunction> function) {
    314   if (!function->has_prototype()) {
    315     Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function);
    316     JSFunction::SetPrototype(function, proto);
    317   }
    318   return Handle<Object>(function->prototype(), isolate);
    319 }
    320 
    321 void Accessors::FunctionPrototypeGetter(
    322     v8::Local<v8::Name> name,
    323     const v8::PropertyCallbackInfo<v8::Value>& info) {
    324   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    325   RuntimeCallTimerScope timer(isolate,
    326                               RuntimeCallCounterId::kFunctionPrototypeGetter);
    327   HandleScope scope(isolate);
    328   Handle<JSFunction> function =
    329       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
    330   DCHECK(function->has_prototype_property());
    331   Handle<Object> result = GetFunctionPrototype(isolate, function);
    332   info.GetReturnValue().Set(Utils::ToLocal(result));
    333 }
    334 
    335 void Accessors::FunctionPrototypeSetter(
    336     v8::Local<v8::Name> name, v8::Local<v8::Value> val,
    337     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
    338   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    339   RuntimeCallTimerScope timer(isolate,
    340                               RuntimeCallCounterId::kFunctionPrototypeSetter);
    341   HandleScope scope(isolate);
    342   Handle<Object> value = Utils::OpenHandle(*val);
    343   Handle<JSFunction> object =
    344       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
    345   DCHECK(object->has_prototype_property());
    346   JSFunction::SetPrototype(object, value);
    347   info.GetReturnValue().Set(true);
    348 }
    349 
    350 Handle<AccessorInfo> Accessors::MakeFunctionPrototypeInfo(Isolate* isolate) {
    351   return MakeAccessor(isolate, isolate->factory()->prototype_string(),
    352                       &FunctionPrototypeGetter, &FunctionPrototypeSetter);
    353 }
    354 
    355 
    356 //
    357 // Accessors::FunctionLength
    358 //
    359 
    360 
    361 void Accessors::FunctionLengthGetter(
    362     v8::Local<v8::Name> name,
    363     const v8::PropertyCallbackInfo<v8::Value>& info) {
    364   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    365   RuntimeCallTimerScope timer(isolate,
    366                               RuntimeCallCounterId::kFunctionLengthGetter);
    367   HandleScope scope(isolate);
    368   Handle<JSFunction> function =
    369       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
    370   int length = 0;
    371   if (!JSFunction::GetLength(isolate, function).To(&length)) {
    372     isolate->OptionalRescheduleException(false);
    373   }
    374   Handle<Object> result(Smi::FromInt(length), isolate);
    375   info.GetReturnValue().Set(Utils::ToLocal(result));
    376 }
    377 
    378 Handle<AccessorInfo> Accessors::MakeFunctionLengthInfo(Isolate* isolate) {
    379   return MakeAccessor(isolate, isolate->factory()->length_string(),
    380                       &FunctionLengthGetter, &ReconfigureToDataProperty);
    381 }
    382 
    383 
    384 //
    385 // Accessors::FunctionName
    386 //
    387 
    388 
    389 void Accessors::FunctionNameGetter(
    390     v8::Local<v8::Name> name,
    391     const v8::PropertyCallbackInfo<v8::Value>& info) {
    392   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    393   HandleScope scope(isolate);
    394   Handle<JSFunction> function =
    395       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
    396   Handle<Object> result = JSFunction::GetName(isolate, function);
    397   info.GetReturnValue().Set(Utils::ToLocal(result));
    398 }
    399 
    400 Handle<AccessorInfo> Accessors::MakeFunctionNameInfo(Isolate* isolate) {
    401   return MakeAccessor(isolate, isolate->factory()->name_string(),
    402                       &FunctionNameGetter, &ReconfigureToDataProperty);
    403 }
    404 
    405 
    406 //
    407 // Accessors::FunctionArguments
    408 //
    409 
    410 namespace {
    411 
    412 Handle<JSObject> ArgumentsForInlinedFunction(JavaScriptFrame* frame,
    413                                              int inlined_frame_index) {
    414   Isolate* isolate = frame->isolate();
    415   Factory* factory = isolate->factory();
    416 
    417   TranslatedState translated_values(frame);
    418   translated_values.Prepare(frame->fp());
    419 
    420   int argument_count = 0;
    421   TranslatedFrame* translated_frame =
    422       translated_values.GetArgumentsInfoFromJSFrameIndex(inlined_frame_index,
    423                                                          &argument_count);
    424   TranslatedFrame::iterator iter = translated_frame->begin();
    425 
    426   // Materialize the function.
    427   bool should_deoptimize = iter->IsMaterializedObject();
    428   Handle<JSFunction> function = Handle<JSFunction>::cast(iter->GetValue());
    429   iter++;
    430 
    431   // Skip the receiver.
    432   iter++;
    433   argument_count--;
    434 
    435   Handle<JSObject> arguments =
    436       factory->NewArgumentsObject(function, argument_count);
    437   Handle<FixedArray> array = factory->NewFixedArray(argument_count);
    438   for (int i = 0; i < argument_count; ++i) {
    439     // If we materialize any object, we should deoptimize the frame because we
    440     // might alias an object that was eliminated by escape analysis.
    441     should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
    442     Handle<Object> value = iter->GetValue();
    443     array->set(i, *value);
    444     iter++;
    445   }
    446   arguments->set_elements(*array);
    447 
    448   if (should_deoptimize) {
    449     translated_values.StoreMaterializedValuesAndDeopt(frame);
    450   }
    451 
    452   // Return the freshly allocated arguments object.
    453   return arguments;
    454 }
    455 
    456 int FindFunctionInFrame(JavaScriptFrame* frame, Handle<JSFunction> function) {
    457   std::vector<FrameSummary> frames;
    458   frame->Summarize(&frames);
    459   for (size_t i = frames.size(); i != 0; i--) {
    460     if (*frames[i - 1].AsJavaScript().function() == *function) {
    461       return static_cast<int>(i) - 1;
    462     }
    463   }
    464   return -1;
    465 }
    466 
    467 Handle<JSObject> GetFrameArguments(Isolate* isolate,
    468                                    JavaScriptFrameIterator* it,
    469                                    int function_index) {
    470   JavaScriptFrame* frame = it->frame();
    471 
    472   if (function_index > 0) {
    473     // The function in question was inlined.  Inlined functions have the
    474     // correct number of arguments and no allocated arguments object, so
    475     // we can construct a fresh one by interpreting the function's
    476     // deoptimization input data.
    477     return ArgumentsForInlinedFunction(frame, function_index);
    478   }
    479 
    480   // Find the frame that holds the actual arguments passed to the function.
    481   if (it->frame()->has_adapted_arguments()) {
    482     it->AdvanceOneFrame();
    483     DCHECK(it->frame()->is_arguments_adaptor());
    484   }
    485   frame = it->frame();
    486 
    487   // Get the number of arguments and construct an arguments object
    488   // mirror for the right frame and the underlying function.
    489   const int length = frame->ComputeParametersCount();
    490   Handle<JSFunction> function(frame->function(), isolate);
    491   Handle<JSObject> arguments =
    492       isolate->factory()->NewArgumentsObject(function, length);
    493   Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
    494 
    495   // Copy the parameters to the arguments object.
    496   DCHECK(array->length() == length);
    497   for (int i = 0; i < length; i++) {
    498     Object* value = frame->GetParameter(i);
    499     if (value->IsTheHole(isolate)) {
    500       // Generators currently use holes as dummy arguments when resuming.  We
    501       // must not leak those.
    502       DCHECK(IsResumableFunction(function->shared()->kind()));
    503       value = ReadOnlyRoots(isolate).undefined_value();
    504     }
    505     array->set(i, value);
    506   }
    507   arguments->set_elements(*array);
    508 
    509   // Return the freshly allocated arguments object.
    510   return arguments;
    511 }
    512 
    513 }  // namespace
    514 
    515 Handle<JSObject> Accessors::FunctionGetArguments(JavaScriptFrame* frame,
    516                                                  int inlined_jsframe_index) {
    517   Isolate* isolate = frame->isolate();
    518   Address requested_frame_fp = frame->fp();
    519   // Forward a frame iterator to the requested frame. This is needed because we
    520   // potentially need for advance it to the arguments adaptor frame later.
    521   for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
    522     if (it.frame()->fp() != requested_frame_fp) continue;
    523     return GetFrameArguments(isolate, &it, inlined_jsframe_index);
    524   }
    525   UNREACHABLE();  // Requested frame not found.
    526   return Handle<JSObject>();
    527 }
    528 
    529 
    530 void Accessors::FunctionArgumentsGetter(
    531     v8::Local<v8::Name> name,
    532     const v8::PropertyCallbackInfo<v8::Value>& info) {
    533   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    534   HandleScope scope(isolate);
    535   Handle<JSFunction> function =
    536       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
    537   Handle<Object> result = isolate->factory()->null_value();
    538   if (!function->shared()->native()) {
    539     // Find the top invocation of the function by traversing frames.
    540     for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
    541       JavaScriptFrame* frame = it.frame();
    542       int function_index = FindFunctionInFrame(frame, function);
    543       if (function_index >= 0) {
    544         result = GetFrameArguments(isolate, &it, function_index);
    545         break;
    546       }
    547     }
    548   }
    549   info.GetReturnValue().Set(Utils::ToLocal(result));
    550 }
    551 
    552 Handle<AccessorInfo> Accessors::MakeFunctionArgumentsInfo(Isolate* isolate) {
    553   return MakeAccessor(isolate, isolate->factory()->arguments_string(),
    554                       &FunctionArgumentsGetter, nullptr);
    555 }
    556 
    557 
    558 //
    559 // Accessors::FunctionCaller
    560 //
    561 
    562 
    563 static inline bool AllowAccessToFunction(Context* current_context,
    564                                          JSFunction* function) {
    565   return current_context->HasSameSecurityTokenAs(function->context());
    566 }
    567 
    568 
    569 class FrameFunctionIterator {
    570  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   bool Find(Handle<JSFunction> function) {
    579     do {
    580       if (!next().ToHandle(&function_)) return false;
    581     } while (!function_.is_identical_to(function));
    582     return true;
    583   }
    584 
    585   // Iterate through functions until the next non-toplevel one is found.
    586   // Returns true if one is found, and false if the iterator ends before.
    587   bool FindNextNonTopLevel() {
    588     do {
    589       if (!next().ToHandle(&function_)) return false;
    590     } while (function_->shared()->is_toplevel());
    591     return true;
    592   }
    593 
    594   // Iterate through function until the first native or user-provided function
    595   // is found. Functions not defined in user-provided scripts are not visible
    596   // unless directly exposed, in which case the native flag is set on them.
    597   // Returns true if one is found, and false if the iterator ends before.
    598   bool FindFirstNativeOrUserJavaScript() {
    599     while (!function_->shared()->native() &&
    600            !function_->shared()->IsUserJavaScript()) {
    601       if (!next().ToHandle(&function_)) return false;
    602     }
    603     return true;
    604   }
    605 
    606   // In case of inlined frames the function could have been materialized from
    607   // deoptimization information. If that is the case we need to make sure that
    608   // subsequent call will see the same function, since we are about to hand out
    609   // the value to JavaScript. Make sure to store the materialized value and
    610   // trigger a deoptimization of the underlying frame.
    611   Handle<JSFunction> MaterializeFunction() {
    612     if (inlined_frame_index_ == 0) return function_;
    613 
    614     JavaScriptFrame* frame = frame_iterator_.frame();
    615     TranslatedState translated_values(frame);
    616     translated_values.Prepare(frame->fp());
    617 
    618     TranslatedFrame* translated_frame =
    619         translated_values.GetFrameFromJSFrameIndex(inlined_frame_index_);
    620     TranslatedFrame::iterator iter = translated_frame->begin();
    621 
    622     // First value is the function.
    623     bool should_deoptimize = iter->IsMaterializedObject();
    624     Handle<Object> value = iter->GetValue();
    625     if (should_deoptimize) {
    626       translated_values.StoreMaterializedValuesAndDeopt(frame);
    627     }
    628 
    629     return Handle<JSFunction>::cast(value);
    630   }
    631 
    632  private:
    633   MaybeHandle<JSFunction> next() {
    634     while (true) {
    635       if (inlined_frame_index_ <= 0) {
    636         if (!frame_iterator_.done()) {
    637           frame_iterator_.Advance();
    638           frames_.clear();
    639           inlined_frame_index_ = -1;
    640           GetFrames();
    641         }
    642         if (inlined_frame_index_ == -1) return MaybeHandle<JSFunction>();
    643       }
    644 
    645       --inlined_frame_index_;
    646       Handle<JSFunction> next_function =
    647           frames_[inlined_frame_index_].AsJavaScript().function();
    648       // Skip functions from other origins.
    649       if (!AllowAccessToFunction(isolate_->context(), *next_function)) continue;
    650       return next_function;
    651     }
    652   }
    653   void GetFrames() {
    654     DCHECK_EQ(-1, inlined_frame_index_);
    655     if (frame_iterator_.done()) return;
    656     JavaScriptFrame* frame = frame_iterator_.frame();
    657     frame->Summarize(&frames_);
    658     inlined_frame_index_ = static_cast<int>(frames_.size());
    659     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 MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
    670                                    Handle<JSFunction> function) {
    671   FrameFunctionIterator it(isolate);
    672   if (function->shared()->native()) {
    673     return MaybeHandle<JSFunction>();
    674   }
    675   // Find the function from the frames. Return null in case no frame
    676   // 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   if (!it.FindNextNonTopLevel()) {
    682     return MaybeHandle<JSFunction>();
    683   }
    684   // Find the first user-land JavaScript function (or the entry point into
    685   // native JavaScript builtins in case such a builtin was the caller).
    686   if (!it.FindFirstNativeOrUserJavaScript()) {
    687     return MaybeHandle<JSFunction>();
    688   }
    689 
    690   // Materialize the function that the iterator is currently sitting on. Note
    691   // that this might trigger deoptimization in case the function was actually
    692   // materialized. Identity of the function must be preserved because we are
    693   // going to return it to JavaScript after this point.
    694   Handle<JSFunction> caller = it.MaterializeFunction();
    695 
    696   // Censor if the caller is not a sloppy mode function.
    697   // Change from ES5, which used to throw, see:
    698   // https://bugs.ecmascript.org/show_bug.cgi?id=310
    699   if (is_strict(caller->shared()->language_mode())) {
    700     return MaybeHandle<JSFunction>();
    701   }
    702   // Don't return caller from another security context.
    703   if (!AllowAccessToFunction(isolate->context(), *caller)) {
    704     return MaybeHandle<JSFunction>();
    705   }
    706   return caller;
    707 }
    708 
    709 
    710 void Accessors::FunctionCallerGetter(
    711     v8::Local<v8::Name> name,
    712     const v8::PropertyCallbackInfo<v8::Value>& info) {
    713   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    714   HandleScope scope(isolate);
    715   Handle<JSFunction> function =
    716       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
    717   Handle<Object> result;
    718   MaybeHandle<JSFunction> maybe_caller;
    719   maybe_caller = FindCaller(isolate, function);
    720   Handle<JSFunction> caller;
    721   if (maybe_caller.ToHandle(&caller)) {
    722     result = caller;
    723   } else {
    724     result = isolate->factory()->null_value();
    725   }
    726   info.GetReturnValue().Set(Utils::ToLocal(result));
    727 }
    728 
    729 Handle<AccessorInfo> Accessors::MakeFunctionCallerInfo(Isolate* isolate) {
    730   return MakeAccessor(isolate, isolate->factory()->caller_string(),
    731                       &FunctionCallerGetter, nullptr);
    732 }
    733 
    734 
    735 //
    736 // Accessors::BoundFunctionLength
    737 //
    738 
    739 void Accessors::BoundFunctionLengthGetter(
    740     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    741   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    742   RuntimeCallTimerScope timer(isolate,
    743                               RuntimeCallCounterId::kBoundFunctionLengthGetter);
    744   HandleScope scope(isolate);
    745   Handle<JSBoundFunction> function =
    746       Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
    747 
    748   int length = 0;
    749   if (!JSBoundFunction::GetLength(isolate, function).To(&length)) {
    750     isolate->OptionalRescheduleException(false);
    751     return;
    752   }
    753   Handle<Object> result(Smi::FromInt(length), isolate);
    754   info.GetReturnValue().Set(Utils::ToLocal(result));
    755 }
    756 
    757 Handle<AccessorInfo> Accessors::MakeBoundFunctionLengthInfo(Isolate* isolate) {
    758   return MakeAccessor(isolate, isolate->factory()->length_string(),
    759                       &BoundFunctionLengthGetter, &ReconfigureToDataProperty);
    760 }
    761 
    762 //
    763 // Accessors::BoundFunctionName
    764 //
    765 
    766 void Accessors::BoundFunctionNameGetter(
    767     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
    768   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    769   RuntimeCallTimerScope timer(isolate,
    770                               RuntimeCallCounterId::kBoundFunctionNameGetter);
    771   HandleScope scope(isolate);
    772   Handle<JSBoundFunction> function =
    773       Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
    774   Handle<Object> result;
    775   if (!JSBoundFunction::GetName(isolate, function).ToHandle(&result)) {
    776     isolate->OptionalRescheduleException(false);
    777     return;
    778   }
    779   info.GetReturnValue().Set(Utils::ToLocal(result));
    780 }
    781 
    782 Handle<AccessorInfo> Accessors::MakeBoundFunctionNameInfo(Isolate* isolate) {
    783   return MakeAccessor(isolate, isolate->factory()->name_string(),
    784                       &BoundFunctionNameGetter, &ReconfigureToDataProperty);
    785 }
    786 
    787 //
    788 // Accessors::ErrorStack
    789 //
    790 
    791 namespace {
    792 
    793 MaybeHandle<JSReceiver> ClearInternalStackTrace(Isolate* isolate,
    794                                                 Handle<JSObject> error) {
    795   RETURN_ON_EXCEPTION(
    796       isolate,
    797       JSReceiver::SetProperty(
    798           isolate, error, isolate->factory()->stack_trace_symbol(),
    799           isolate->factory()->undefined_value(), LanguageMode::kStrict),
    800       JSReceiver);
    801   return error;
    802 }
    803 
    804 bool IsAccessor(Handle<Object> receiver, Handle<Name> name,
    805                 Handle<JSObject> holder) {
    806   LookupIterator it(receiver, name, holder,
    807                     LookupIterator::OWN_SKIP_INTERCEPTOR);
    808   // Skip any access checks we might hit. This accessor should never hit in a
    809   // situation where the caller does not have access.
    810   if (it.state() == LookupIterator::ACCESS_CHECK) {
    811     CHECK(it.HasAccess());
    812     it.Next();
    813   }
    814   return (it.state() == LookupIterator::ACCESSOR);
    815 }
    816 
    817 }  // namespace
    818 
    819 void Accessors::ErrorStackGetter(
    820     v8::Local<v8::Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
    821   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    822   HandleScope scope(isolate);
    823   Handle<JSObject> holder =
    824       Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
    825 
    826   // Retrieve the structured stack trace.
    827 
    828   Handle<Object> stack_trace;
    829   Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
    830   MaybeHandle<Object> maybe_stack_trace =
    831       JSObject::GetProperty(isolate, holder, stack_trace_symbol);
    832   if (!maybe_stack_trace.ToHandle(&stack_trace) ||
    833       stack_trace->IsUndefined(isolate)) {
    834     Handle<Object> result = isolate->factory()->undefined_value();
    835     info.GetReturnValue().Set(Utils::ToLocal(result));
    836     return;
    837   }
    838 
    839   // Format it, clear the internal structured trace and reconfigure as a data
    840   // property.
    841 
    842   Handle<Object> formatted_stack_trace;
    843   if (!ErrorUtils::FormatStackTrace(isolate, holder, stack_trace)
    844            .ToHandle(&formatted_stack_trace)) {
    845     isolate->OptionalRescheduleException(false);
    846     return;
    847   }
    848 
    849   MaybeHandle<Object> result = ClearInternalStackTrace(isolate, holder);
    850   if (result.is_null()) {
    851     isolate->OptionalRescheduleException(false);
    852     return;
    853   }
    854 
    855   // If stack is still an accessor (this could have changed in the meantime
    856   // since FormatStackTrace can execute arbitrary JS), replace it with a data
    857   // property.
    858   Handle<Object> receiver =
    859       Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
    860   Handle<Name> name = Utils::OpenHandle(*key);
    861   if (IsAccessor(receiver, name, holder)) {
    862     result = Accessors::ReplaceAccessorWithDataProperty(receiver, holder, name,
    863                                                         formatted_stack_trace);
    864     if (result.is_null()) {
    865       isolate->OptionalRescheduleException(false);
    866       return;
    867     }
    868   } else {
    869     // The stack property has been modified in the meantime.
    870     if (!JSObject::GetProperty(isolate, holder, name)
    871              .ToHandle(&formatted_stack_trace)) {
    872       isolate->OptionalRescheduleException(false);
    873       return;
    874     }
    875   }
    876 
    877   v8::Local<v8::Value> value = Utils::ToLocal(formatted_stack_trace);
    878   info.GetReturnValue().Set(value);
    879 }
    880 
    881 void Accessors::ErrorStackSetter(
    882     v8::Local<v8::Name> name, v8::Local<v8::Value> val,
    883     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
    884   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
    885   HandleScope scope(isolate);
    886   Handle<JSObject> obj = Handle<JSObject>::cast(
    887       Utils::OpenHandle(*v8::Local<v8::Value>(info.This())));
    888 
    889   // Clear internal properties to avoid memory leaks.
    890   Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
    891   if (JSReceiver::HasOwnProperty(obj, stack_trace_symbol).FromMaybe(false)) {
    892     ClearInternalStackTrace(isolate, obj);
    893   }
    894 
    895   Accessors::ReconfigureToDataProperty(name, val, info);
    896 }
    897 
    898 Handle<AccessorInfo> Accessors::MakeErrorStackInfo(Isolate* isolate) {
    899   return MakeAccessor(isolate, isolate->factory()->stack_string(),
    900                       &ErrorStackGetter, &ErrorStackSetter);
    901 }
    902 
    903 }  // namespace internal
    904 }  // namespace v8
    905