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