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