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