• 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/debug/debug.h"
9 #include "src/deoptimizer/deoptimizer.h"
10 #include "src/execution/execution.h"
11 #include "src/execution/frames-inl.h"
12 #include "src/execution/isolate-inl.h"
13 #include "src/execution/messages.h"
14 #include "src/heap/factory.h"
15 #include "src/logging/runtime-call-stats-scope.h"
16 #include "src/objects/api-callbacks.h"
17 #include "src/objects/contexts.h"
18 #include "src/objects/field-index-inl.h"
19 #include "src/objects/js-array-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   if (map->is_dictionary_map()) {
70     // There are not descriptors in a dictionary mode map.
71     return false;
72   }
73 
74   switch (map->instance_type()) {
75     case JS_ARRAY_TYPE:
76       return CheckForName(isolate, name, isolate->factory()->length_string(),
77                           JSArray::kLengthOffset, FieldIndex::kTagged, index);
78     default:
79       if (map->instance_type() < FIRST_NONSTRING_TYPE) {
80         return CheckForName(isolate, name, isolate->factory()->length_string(),
81                             String::kLengthOffset, FieldIndex::kWord32, index);
82       }
83 
84       return false;
85   }
86 }
87 
88 V8_WARN_UNUSED_RESULT MaybeHandle<Object>
ReplaceAccessorWithDataProperty(Isolate * isolate,Handle<Object> receiver,Handle<JSObject> holder,Handle<Name> name,Handle<Object> value)89 Accessors::ReplaceAccessorWithDataProperty(Isolate* isolate,
90                                            Handle<Object> receiver,
91                                            Handle<JSObject> holder,
92                                            Handle<Name> name,
93                                            Handle<Object> value) {
94   LookupIterator it(isolate, receiver, PropertyKey(isolate, name), holder,
95                     LookupIterator::OWN_SKIP_INTERCEPTOR);
96   // Skip any access checks we might hit. This accessor should never hit in a
97   // situation where the caller does not have access.
98   if (it.state() == LookupIterator::ACCESS_CHECK) {
99     CHECK(it.HasAccess());
100     it.Next();
101   }
102   DCHECK(holder.is_identical_to(it.GetHolder<JSObject>()));
103   CHECK_EQ(LookupIterator::ACCESSOR, it.state());
104   it.ReconfigureDataProperty(value, it.property_attributes());
105   return value;
106 }
107 
108 //
109 // Accessors::ReconfigureToDataProperty
110 //
ReconfigureToDataProperty(v8::Local<v8::Name> key,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)111 void Accessors::ReconfigureToDataProperty(
112     v8::Local<v8::Name> key, v8::Local<v8::Value> val,
113     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
114   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
115   RCS_SCOPE(isolate, RuntimeCallCounterId::kReconfigureToDataProperty);
116   HandleScope scope(isolate);
117   Handle<Object> receiver = Utils::OpenHandle(*info.This());
118   Handle<JSObject> holder =
119       Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
120   Handle<Name> name = Utils::OpenHandle(*key);
121   Handle<Object> value = Utils::OpenHandle(*val);
122   MaybeHandle<Object> result = Accessors::ReplaceAccessorWithDataProperty(
123       isolate, receiver, holder, name, value);
124   if (result.is_null()) {
125     isolate->OptionalRescheduleException(false);
126   } else {
127     info.GetReturnValue().Set(true);
128   }
129 }
130 
131 //
132 // Accessors::ArgumentsIterator
133 //
134 
ArgumentsIteratorGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)135 void Accessors::ArgumentsIteratorGetter(
136     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
137   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
138   DisallowGarbageCollection no_gc;
139   HandleScope scope(isolate);
140   Object result = isolate->native_context()->array_values_iterator();
141   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
142 }
143 
MakeArgumentsIteratorInfo(Isolate * isolate)144 Handle<AccessorInfo> Accessors::MakeArgumentsIteratorInfo(Isolate* isolate) {
145   Handle<Name> name = isolate->factory()->iterator_symbol();
146   return MakeAccessor(isolate, name, &ArgumentsIteratorGetter, nullptr);
147 }
148 
149 //
150 // Accessors::ArrayLength
151 //
152 
ArrayLengthGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)153 void Accessors::ArrayLengthGetter(
154     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
155   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
156   RCS_SCOPE(isolate, RuntimeCallCounterId::kArrayLengthGetter);
157   DisallowGarbageCollection no_gc;
158   HandleScope scope(isolate);
159   JSArray holder = JSArray::cast(*Utils::OpenHandle(*info.Holder()));
160   Object result = holder.length();
161   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
162 }
163 
ArrayLengthSetter(v8::Local<v8::Name> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)164 void Accessors::ArrayLengthSetter(
165     v8::Local<v8::Name> name, v8::Local<v8::Value> val,
166     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
167   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
168   RCS_SCOPE(isolate, 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     // AnythingToArrayLength() may have called setter re-entrantly and modified
188     // its property descriptor. Don't perform this check if "length" was
189     // previously readonly, as this may have been called during
190     // DefineOwnPropertyIgnoreAttributes().
191     if (length == array->length().Number()) {
192       info.GetReturnValue().Set(true);
193     } else if (info.ShouldThrowOnError()) {
194       Factory* factory = isolate->factory();
195       isolate->Throw(*factory->NewTypeError(
196           MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
197           i::Object::TypeOf(isolate, object), object));
198       isolate->OptionalRescheduleException(false);
199     } else {
200       info.GetReturnValue().Set(false);
201     }
202     return;
203   }
204 
205   if (JSArray::SetLength(array, length).IsNothing()) {
206     // TODO(victorgomes): AccessorNameBooleanSetterCallback does not handle
207     // exceptions.
208     FATAL("Fatal JavaScript invalid array length %u", length);
209     UNREACHABLE();
210   }
211 
212   uint32_t actual_new_len = 0;
213   CHECK(array->length().ToArrayLength(&actual_new_len));
214   // Fail if there were non-deletable elements.
215   if (actual_new_len != length) {
216     if (info.ShouldThrowOnError()) {
217       Factory* factory = isolate->factory();
218       isolate->Throw(*factory->NewTypeError(
219           MessageTemplate::kStrictDeleteProperty,
220           factory->NewNumberFromUint(actual_new_len - 1), array));
221       isolate->OptionalRescheduleException(false);
222     } else {
223       info.GetReturnValue().Set(false);
224     }
225   } else {
226     info.GetReturnValue().Set(true);
227   }
228 }
229 
MakeArrayLengthInfo(Isolate * isolate)230 Handle<AccessorInfo> Accessors::MakeArrayLengthInfo(Isolate* isolate) {
231   return MakeAccessor(isolate, isolate->factory()->length_string(),
232                       &ArrayLengthGetter, &ArrayLengthSetter);
233 }
234 
235 //
236 // Accessors::ModuleNamespaceEntry
237 //
238 
ModuleNamespaceEntryGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)239 void Accessors::ModuleNamespaceEntryGetter(
240     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
241   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
242   HandleScope scope(isolate);
243   JSModuleNamespace holder =
244       JSModuleNamespace::cast(*Utils::OpenHandle(*info.Holder()));
245   Handle<Object> result;
246   if (!holder.GetExport(isolate, Handle<String>::cast(Utils::OpenHandle(*name)))
247            .ToHandle(&result)) {
248     isolate->OptionalRescheduleException(false);
249   } else {
250     info.GetReturnValue().Set(Utils::ToLocal(result));
251   }
252 }
253 
ModuleNamespaceEntrySetter(v8::Local<v8::Name> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)254 void Accessors::ModuleNamespaceEntrySetter(
255     v8::Local<v8::Name> name, v8::Local<v8::Value> val,
256     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
257   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
258   HandleScope scope(isolate);
259   Factory* factory = isolate->factory();
260   Handle<JSModuleNamespace> holder =
261       Handle<JSModuleNamespace>::cast(Utils::OpenHandle(*info.Holder()));
262 
263   if (info.ShouldThrowOnError()) {
264     isolate->Throw(*factory->NewTypeError(
265         MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
266         i::Object::TypeOf(isolate, holder), holder));
267     isolate->OptionalRescheduleException(false);
268   } else {
269     info.GetReturnValue().Set(false);
270   }
271 }
272 
MakeModuleNamespaceEntryInfo(Isolate * isolate,Handle<String> name)273 Handle<AccessorInfo> Accessors::MakeModuleNamespaceEntryInfo(
274     Isolate* isolate, Handle<String> name) {
275   return MakeAccessor(isolate, name, &ModuleNamespaceEntryGetter,
276                       &ModuleNamespaceEntrySetter);
277 }
278 
279 //
280 // Accessors::StringLength
281 //
282 
StringLengthGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)283 void Accessors::StringLengthGetter(
284     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
285   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
286   RCS_SCOPE(isolate, RuntimeCallCounterId::kStringLengthGetter);
287   DisallowGarbageCollection no_gc;
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 =
300         JSPrimitiveWrapper::cast(*Utils::OpenHandle(*info.Holder())).value();
301   }
302   Object result = Smi::FromInt(String::cast(value).length());
303   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
304 }
305 
MakeStringLengthInfo(Isolate * isolate)306 Handle<AccessorInfo> Accessors::MakeStringLengthInfo(Isolate* isolate) {
307   return MakeAccessor(isolate, isolate->factory()->length_string(),
308                       &StringLengthGetter, nullptr);
309 }
310 
311 //
312 // Accessors::FunctionPrototype
313 //
314 
GetFunctionPrototype(Isolate * isolate,Handle<JSFunction> function)315 static Handle<Object> GetFunctionPrototype(Isolate* isolate,
316                                            Handle<JSFunction> function) {
317   if (!function->has_prototype()) {
318     // We lazily allocate .prototype for functions, which confuses debug
319     // evaluate which assumes we can write to temporary objects we allocated
320     // during evaluation. We err on the side of caution here and prevent the
321     // newly allocated prototype from going into the temporary objects set,
322     // which means writes to it will be considered a side effect.
323     DisableTemporaryObjectTracking no_temp_tracking(isolate->debug());
324     Handle<JSObject> proto = isolate->factory()->NewFunctionPrototype(function);
325     JSFunction::SetPrototype(function, proto);
326   }
327   return Handle<Object>(function->prototype(), isolate);
328 }
329 
FunctionPrototypeGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)330 void Accessors::FunctionPrototypeGetter(
331     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
332   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
333   RCS_SCOPE(isolate, RuntimeCallCounterId::kFunctionPrototypeGetter);
334   HandleScope scope(isolate);
335   Handle<JSFunction> function =
336       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
337   DCHECK(function->has_prototype_property());
338   Handle<Object> result = GetFunctionPrototype(isolate, function);
339   info.GetReturnValue().Set(Utils::ToLocal(result));
340 }
341 
FunctionPrototypeSetter(v8::Local<v8::Name> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)342 void Accessors::FunctionPrototypeSetter(
343     v8::Local<v8::Name> name, v8::Local<v8::Value> val,
344     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
345   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
346   RCS_SCOPE(isolate, RuntimeCallCounterId::kFunctionPrototypeSetter);
347   HandleScope scope(isolate);
348   Handle<Object> value = Utils::OpenHandle(*val);
349   Handle<JSFunction> object =
350       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
351   DCHECK(object->has_prototype_property());
352   JSFunction::SetPrototype(object, value);
353   info.GetReturnValue().Set(true);
354 }
355 
MakeFunctionPrototypeInfo(Isolate * isolate)356 Handle<AccessorInfo> Accessors::MakeFunctionPrototypeInfo(Isolate* isolate) {
357   return MakeAccessor(isolate, isolate->factory()->prototype_string(),
358                       &FunctionPrototypeGetter, &FunctionPrototypeSetter);
359 }
360 
361 //
362 // Accessors::FunctionLength
363 //
364 
FunctionLengthGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)365 void Accessors::FunctionLengthGetter(
366     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
367   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
368   RCS_SCOPE(isolate, RuntimeCallCounterId::kFunctionLengthGetter);
369   HandleScope scope(isolate);
370   Handle<JSFunction> function =
371       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
372   int length = function->length();
373   Handle<Object> result(Smi::FromInt(length), isolate);
374   info.GetReturnValue().Set(Utils::ToLocal(result));
375 }
376 
MakeFunctionLengthInfo(Isolate * isolate)377 Handle<AccessorInfo> Accessors::MakeFunctionLengthInfo(Isolate* isolate) {
378   return MakeAccessor(isolate, isolate->factory()->length_string(),
379                       &FunctionLengthGetter, &ReconfigureToDataProperty);
380 }
381 
382 //
383 // Accessors::FunctionName
384 //
385 
FunctionNameGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)386 void Accessors::FunctionNameGetter(
387     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
388   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
389   HandleScope scope(isolate);
390   Handle<JSFunction> function =
391       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
392   Handle<Object> result = JSFunction::GetName(isolate, function);
393   info.GetReturnValue().Set(Utils::ToLocal(result));
394 }
395 
MakeFunctionNameInfo(Isolate * isolate)396 Handle<AccessorInfo> Accessors::MakeFunctionNameInfo(Isolate* isolate) {
397   return MakeAccessor(isolate, isolate->factory()->name_string(),
398                       &FunctionNameGetter, &ReconfigureToDataProperty);
399 }
400 
401 //
402 // Accessors::FunctionArguments
403 //
404 
405 namespace {
406 
ArgumentsForInlinedFunction(JavaScriptFrame * frame,int inlined_frame_index)407 Handle<JSObject> ArgumentsForInlinedFunction(JavaScriptFrame* frame,
408                                              int inlined_frame_index) {
409   Isolate* isolate = frame->isolate();
410   Factory* factory = isolate->factory();
411 
412   TranslatedState translated_values(frame);
413   translated_values.Prepare(frame->fp());
414 
415   int argument_count = 0;
416   TranslatedFrame* translated_frame =
417       translated_values.GetArgumentsInfoFromJSFrameIndex(inlined_frame_index,
418                                                          &argument_count);
419   TranslatedFrame::iterator iter = translated_frame->begin();
420 
421   // Materialize the function.
422   bool should_deoptimize = iter->IsMaterializedObject();
423   Handle<JSFunction> function = Handle<JSFunction>::cast(iter->GetValue());
424   iter++;
425 
426   // Skip the receiver.
427   iter++;
428   argument_count--;
429 
430   Handle<JSObject> arguments =
431       factory->NewArgumentsObject(function, argument_count);
432   Handle<FixedArray> array = factory->NewFixedArray(argument_count);
433   for (int i = 0; i < argument_count; ++i) {
434     // If we materialize any object, we should deoptimize the frame because we
435     // might alias an object that was eliminated by escape analysis.
436     should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
437     Handle<Object> value = iter->GetValue();
438     array->set(i, *value);
439     iter++;
440   }
441   arguments->set_elements(*array);
442 
443   if (should_deoptimize) {
444     translated_values.StoreMaterializedValuesAndDeopt(frame);
445   }
446 
447   // Return the freshly allocated arguments object.
448   return arguments;
449 }
450 
FindFunctionInFrame(JavaScriptFrame * frame,Handle<JSFunction> function)451 int FindFunctionInFrame(JavaScriptFrame* frame, Handle<JSFunction> function) {
452   std::vector<FrameSummary> frames;
453   frame->Summarize(&frames);
454   for (size_t i = frames.size(); i != 0; i--) {
455     if (*frames[i - 1].AsJavaScript().function() == *function) {
456       return static_cast<int>(i) - 1;
457     }
458   }
459   return -1;
460 }
461 
GetFrameArguments(Isolate * isolate,JavaScriptFrameIterator * it,int function_index)462 Handle<JSObject> GetFrameArguments(Isolate* isolate,
463                                    JavaScriptFrameIterator* it,
464                                    int function_index) {
465   JavaScriptFrame* frame = it->frame();
466 
467   if (function_index > 0) {
468     // The function in question was inlined.  Inlined functions have the
469     // correct number of arguments and no allocated arguments object, so
470     // we can construct a fresh one by interpreting the function's
471     // deoptimization input data.
472     return ArgumentsForInlinedFunction(frame, function_index);
473   }
474 
475   // Construct an arguments object mirror for the right frame and the underlying
476   // function.
477   const int length = frame->GetActualArgumentCount();
478   Handle<JSFunction> function(frame->function(), isolate);
479   Handle<JSObject> arguments =
480       isolate->factory()->NewArgumentsObject(function, length);
481   Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
482 
483   // Copy the parameters to the arguments object.
484   DCHECK(array->length() == length);
485   for (int i = 0; i < length; i++) {
486     Object value = frame->GetParameter(i);
487     if (value.IsTheHole(isolate)) {
488       // Generators currently use holes as dummy arguments when resuming.  We
489       // must not leak those.
490       DCHECK(IsResumableFunction(function->shared().kind()));
491       value = ReadOnlyRoots(isolate).undefined_value();
492     }
493     array->set(i, value);
494   }
495   arguments->set_elements(*array);
496 
497   // Return the freshly allocated arguments object.
498   return arguments;
499 }
500 
501 }  // namespace
502 
FunctionGetArguments(JavaScriptFrame * frame,int inlined_jsframe_index)503 Handle<JSObject> Accessors::FunctionGetArguments(JavaScriptFrame* frame,
504                                                  int inlined_jsframe_index) {
505   Isolate* isolate = frame->isolate();
506   Address requested_frame_fp = frame->fp();
507   // Forward a frame iterator to the requested frame. This is needed because we
508   // potentially need for advance it to the arguments adaptor frame later.
509   for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
510     if (it.frame()->fp() != requested_frame_fp) continue;
511     return GetFrameArguments(isolate, &it, inlined_jsframe_index);
512   }
513   UNREACHABLE();  // Requested frame not found.
514 }
515 
FunctionArgumentsGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)516 void Accessors::FunctionArgumentsGetter(
517     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
518   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
519   isolate->CountUsage(v8::Isolate::kFunctionPrototypeArguments);
520   HandleScope scope(isolate);
521   Handle<JSFunction> function =
522       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
523   Handle<Object> result = isolate->factory()->null_value();
524   if (!function->shared().native()) {
525     // Find the top invocation of the function by traversing frames.
526     for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
527       JavaScriptFrame* frame = it.frame();
528       int function_index = FindFunctionInFrame(frame, function);
529       if (function_index >= 0) {
530         result = GetFrameArguments(isolate, &it, function_index);
531         break;
532       }
533     }
534   }
535   info.GetReturnValue().Set(Utils::ToLocal(result));
536 }
537 
MakeFunctionArgumentsInfo(Isolate * isolate)538 Handle<AccessorInfo> Accessors::MakeFunctionArgumentsInfo(Isolate* isolate) {
539   return MakeAccessor(isolate, isolate->factory()->arguments_string(),
540                       &FunctionArgumentsGetter, nullptr);
541 }
542 
543 //
544 // Accessors::FunctionCaller
545 //
546 
AllowAccessToFunction(Context current_context,JSFunction function)547 static inline bool AllowAccessToFunction(Context current_context,
548                                          JSFunction function) {
549   return current_context.HasSameSecurityTokenAs(function.context());
550 }
551 
552 class FrameFunctionIterator {
553  public:
FrameFunctionIterator(Isolate * isolate)554   explicit FrameFunctionIterator(Isolate* isolate)
555       : isolate_(isolate), frame_iterator_(isolate), inlined_frame_index_(-1) {
556     GetFrames();
557   }
558 
559   // Iterate through functions until the first occurrence of 'function'.
560   // Returns true if one is found, and false if the iterator ends before.
Find(Handle<JSFunction> function)561   bool Find(Handle<JSFunction> function) {
562     do {
563       if (!next().ToHandle(&function_)) return false;
564     } while (!function_.is_identical_to(function));
565     return true;
566   }
567 
568   // Iterate through functions until the next non-toplevel one is found.
569   // Returns true if one is found, and false if the iterator ends before.
FindNextNonTopLevel()570   bool FindNextNonTopLevel() {
571     do {
572       if (!next().ToHandle(&function_)) return false;
573     } while (function_->shared().is_toplevel());
574     return true;
575   }
576 
577   // Iterate through function until the first native or user-provided function
578   // is found. Functions not defined in user-provided scripts are not visible
579   // unless directly exposed, in which case the native flag is set on them.
580   // Returns true if one is found, and false if the iterator ends before.
FindFirstNativeOrUserJavaScript()581   bool FindFirstNativeOrUserJavaScript() {
582     while (!function_->shared().native() &&
583            !function_->shared().IsUserJavaScript()) {
584       if (!next().ToHandle(&function_)) return false;
585     }
586     return true;
587   }
588 
589   // In case of inlined frames the function could have been materialized from
590   // deoptimization information. If that is the case we need to make sure that
591   // subsequent call will see the same function, since we are about to hand out
592   // the value to JavaScript. Make sure to store the materialized value and
593   // trigger a deoptimization of the underlying frame.
MaterializeFunction()594   Handle<JSFunction> MaterializeFunction() {
595     if (inlined_frame_index_ == 0) return function_;
596 
597     JavaScriptFrame* frame = frame_iterator_.frame();
598     TranslatedState translated_values(frame);
599     translated_values.Prepare(frame->fp());
600 
601     TranslatedFrame* translated_frame =
602         translated_values.GetFrameFromJSFrameIndex(inlined_frame_index_);
603     TranslatedFrame::iterator iter = translated_frame->begin();
604 
605     // First value is the function.
606     bool should_deoptimize = iter->IsMaterializedObject();
607     Handle<Object> value = iter->GetValue();
608     if (should_deoptimize) {
609       translated_values.StoreMaterializedValuesAndDeopt(frame);
610     }
611 
612     return Handle<JSFunction>::cast(value);
613   }
614 
615  private:
next()616   MaybeHandle<JSFunction> next() {
617     while (true) {
618       if (inlined_frame_index_ <= 0) {
619         if (!frame_iterator_.done()) {
620           frame_iterator_.Advance();
621           frames_.clear();
622           inlined_frame_index_ = -1;
623           GetFrames();
624         }
625         if (inlined_frame_index_ == -1) return MaybeHandle<JSFunction>();
626       }
627 
628       --inlined_frame_index_;
629       Handle<JSFunction> next_function =
630           frames_[inlined_frame_index_].AsJavaScript().function();
631       // Skip functions from other origins.
632       if (!AllowAccessToFunction(isolate_->context(), *next_function)) continue;
633       return next_function;
634     }
635   }
GetFrames()636   void GetFrames() {
637     DCHECK_EQ(-1, inlined_frame_index_);
638     if (frame_iterator_.done()) return;
639     JavaScriptFrame* frame = frame_iterator_.frame();
640     frame->Summarize(&frames_);
641     inlined_frame_index_ = static_cast<int>(frames_.size());
642     DCHECK_LT(0, inlined_frame_index_);
643   }
644   Isolate* isolate_;
645   Handle<JSFunction> function_;
646   JavaScriptFrameIterator frame_iterator_;
647   std::vector<FrameSummary> frames_;
648   int inlined_frame_index_;
649 };
650 
FindCaller(Isolate * isolate,Handle<JSFunction> function)651 MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
652                                    Handle<JSFunction> function) {
653   FrameFunctionIterator it(isolate);
654   if (function->shared().native()) {
655     return MaybeHandle<JSFunction>();
656   }
657   // Find the function from the frames. Return null in case no frame
658   // corresponding to the given function was found.
659   if (!it.Find(function)) {
660     return MaybeHandle<JSFunction>();
661   }
662   // Find previously called non-toplevel function.
663   if (!it.FindNextNonTopLevel()) {
664     return MaybeHandle<JSFunction>();
665   }
666   // Find the first user-land JavaScript function (or the entry point into
667   // native JavaScript builtins in case such a builtin was the caller).
668   if (!it.FindFirstNativeOrUserJavaScript()) {
669     return MaybeHandle<JSFunction>();
670   }
671 
672   // Materialize the function that the iterator is currently sitting on. Note
673   // that this might trigger deoptimization in case the function was actually
674   // materialized. Identity of the function must be preserved because we are
675   // going to return it to JavaScript after this point.
676   Handle<JSFunction> caller = it.MaterializeFunction();
677 
678   // Censor if the caller is not a sloppy mode function.
679   // Change from ES5, which used to throw, see:
680   // https://bugs.ecmascript.org/show_bug.cgi?id=310
681   if (is_strict(caller->shared().language_mode())) {
682     return MaybeHandle<JSFunction>();
683   }
684   // Don't return caller from another security context.
685   if (!AllowAccessToFunction(isolate->context(), *caller)) {
686     return MaybeHandle<JSFunction>();
687   }
688   return caller;
689 }
690 
FunctionCallerGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)691 void Accessors::FunctionCallerGetter(
692     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
693   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
694   isolate->CountUsage(v8::Isolate::kFunctionPrototypeCaller);
695   HandleScope scope(isolate);
696   Handle<JSFunction> function =
697       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
698   Handle<Object> result;
699   MaybeHandle<JSFunction> maybe_caller;
700   maybe_caller = FindCaller(isolate, function);
701   Handle<JSFunction> caller;
702   // We don't support caller access with correctness fuzzing.
703   if (!FLAG_correctness_fuzzer_suppressions && 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   RCS_SCOPE(isolate, RuntimeCallCounterId::kBoundFunctionLengthGetter);
724   HandleScope scope(isolate);
725   Handle<JSBoundFunction> function =
726       Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
727 
728   int length = 0;
729   if (!JSBoundFunction::GetLength(isolate, function).To(&length)) {
730     isolate->OptionalRescheduleException(false);
731     return;
732   }
733   Handle<Object> result(Smi::FromInt(length), isolate);
734   info.GetReturnValue().Set(Utils::ToLocal(result));
735 }
736 
MakeBoundFunctionLengthInfo(Isolate * isolate)737 Handle<AccessorInfo> Accessors::MakeBoundFunctionLengthInfo(Isolate* isolate) {
738   return MakeAccessor(isolate, isolate->factory()->length_string(),
739                       &BoundFunctionLengthGetter, &ReconfigureToDataProperty);
740 }
741 
742 //
743 // Accessors::BoundFunctionName
744 //
745 
BoundFunctionNameGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)746 void Accessors::BoundFunctionNameGetter(
747     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
748   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
749   RCS_SCOPE(isolate, RuntimeCallCounterId::kBoundFunctionNameGetter);
750   HandleScope scope(isolate);
751   Handle<JSBoundFunction> function =
752       Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
753   Handle<Object> result;
754   if (!JSBoundFunction::GetName(isolate, function).ToHandle(&result)) {
755     isolate->OptionalRescheduleException(false);
756     return;
757   }
758   info.GetReturnValue().Set(Utils::ToLocal(result));
759 }
760 
MakeBoundFunctionNameInfo(Isolate * isolate)761 Handle<AccessorInfo> Accessors::MakeBoundFunctionNameInfo(Isolate* isolate) {
762   return MakeAccessor(isolate, isolate->factory()->name_string(),
763                       &BoundFunctionNameGetter, &ReconfigureToDataProperty);
764 }
765 
766 //
767 // Accessors::WrappedFunctionLength
768 //
769 
WrappedFunctionLengthGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)770 void Accessors::WrappedFunctionLengthGetter(
771     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
772   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
773   RCS_SCOPE(isolate, RuntimeCallCounterId::kBoundFunctionLengthGetter);
774   HandleScope scope(isolate);
775   Handle<JSWrappedFunction> function =
776       Handle<JSWrappedFunction>::cast(Utils::OpenHandle(*info.Holder()));
777 
778   int length = 0;
779   if (!JSWrappedFunction::GetLength(isolate, function).To(&length)) {
780     isolate->OptionalRescheduleException(false);
781     return;
782   }
783   Handle<Object> result(Smi::FromInt(length), isolate);
784   info.GetReturnValue().Set(Utils::ToLocal(result));
785 }
786 
MakeWrappedFunctionLengthInfo(Isolate * isolate)787 Handle<AccessorInfo> Accessors::MakeWrappedFunctionLengthInfo(
788     Isolate* isolate) {
789   return MakeAccessor(isolate, isolate->factory()->length_string(),
790                       &WrappedFunctionLengthGetter, &ReconfigureToDataProperty);
791 }
792 
793 //
794 // Accessors::WrappedFunctionName
795 //
796 
WrappedFunctionNameGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)797 void Accessors::WrappedFunctionNameGetter(
798     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
799   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
800   RCS_SCOPE(isolate, RuntimeCallCounterId::kWrappedFunctionNameGetter);
801   HandleScope scope(isolate);
802   Handle<JSWrappedFunction> function =
803       Handle<JSWrappedFunction>::cast(Utils::OpenHandle(*info.Holder()));
804   Handle<Object> result;
805   if (!JSWrappedFunction::GetName(isolate, function).ToHandle(&result)) {
806     isolate->OptionalRescheduleException(false);
807     return;
808   }
809   info.GetReturnValue().Set(Utils::ToLocal(result));
810 }
811 
MakeWrappedFunctionNameInfo(Isolate * isolate)812 Handle<AccessorInfo> Accessors::MakeWrappedFunctionNameInfo(Isolate* isolate) {
813   return MakeAccessor(isolate, isolate->factory()->name_string(),
814                       &WrappedFunctionNameGetter, &ReconfigureToDataProperty);
815 }
816 
817 //
818 // Accessors::ErrorStack
819 //
820 
ErrorStackGetter(v8::Local<v8::Name> key,const v8::PropertyCallbackInfo<v8::Value> & info)821 void Accessors::ErrorStackGetter(
822     v8::Local<v8::Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
823   Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate());
824   HandleScope scope(isolate);
825   Handle<Object> formatted_stack;
826   Handle<JSObject> error_object =
827       Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
828   if (!ErrorUtils::GetFormattedStack(isolate, error_object)
829            .ToHandle(&formatted_stack)) {
830     isolate->OptionalRescheduleException(false);
831     return;
832   }
833   info.GetReturnValue().Set(Utils::ToLocal(formatted_stack));
834 }
835 
ErrorStackSetter(v8::Local<v8::Name> name,v8::Local<v8::Value> value,const v8::PropertyCallbackInfo<v8::Boolean> & info)836 void Accessors::ErrorStackSetter(
837     v8::Local<v8::Name> name, v8::Local<v8::Value> value,
838     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
839   Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate());
840   HandleScope scope(isolate);
841   Handle<JSObject> error_object =
842       Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
843   ErrorUtils::SetFormattedStack(isolate, error_object,
844                                 Utils::OpenHandle(*value));
845 }
846 
MakeErrorStackInfo(Isolate * isolate)847 Handle<AccessorInfo> Accessors::MakeErrorStackInfo(Isolate* isolate) {
848   return MakeAccessor(isolate, isolate->factory()->stack_string(),
849                       &ErrorStackGetter, &ErrorStackSetter);
850 }
851 
852 }  // namespace internal
853 }  // namespace v8
854