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.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/property-details.h"
17 #include "src/prototype.h"
18 
19 namespace v8 {
20 namespace internal {
21 
MakeAccessor(Isolate * isolate,Handle<Name> name,AccessorNameGetterCallback getter,AccessorNameBooleanSetterCallback setter)22 Handle<AccessorInfo> Accessors::MakeAccessor(
23     Isolate* isolate, Handle<Name> name, AccessorNameGetterCallback getter,
24     AccessorNameBooleanSetterCallback setter) {
25   Factory* factory = isolate->factory();
26   Handle<AccessorInfo> info = factory->NewAccessorInfo();
27   info->set_all_can_read(false);
28   info->set_all_can_write(false);
29   info->set_is_special_data_property(true);
30   info->set_is_sloppy(false);
31   info->set_replace_on_access(false);
32   info->set_has_no_side_effect(false);
33   name = factory->InternalizeName(name);
34   info->set_name(*name);
35   Handle<Object> get = v8::FromCData(isolate, getter);
36   if (setter == nullptr) setter = &ReconfigureToDataProperty;
37   Handle<Object> set = v8::FromCData(isolate, setter);
38   info->set_getter(*get);
39   info->set_setter(*set);
40   Address redirected = info->redirected_getter();
41   if (redirected != kNullAddress) {
42     Handle<Object> js_get = v8::FromCData(isolate, redirected);
43     info->set_js_getter(*js_get);
44   }
45   return info;
46 }
47 
CheckForName(Handle<Name> name,Handle<String> property_name,int offset,FieldIndex::Encoding encoding,FieldIndex * index)48 static V8_INLINE bool CheckForName(Handle<Name> name,
49                                    Handle<String> property_name, int offset,
50                                    FieldIndex::Encoding encoding,
51                                    FieldIndex* index) {
52   if (Name::Equals(name, property_name)) {
53     *index = FieldIndex::ForInObjectOffset(offset, encoding);
54     return true;
55   }
56   return false;
57 }
58 
59 
60 // Returns true for properties that are accessors to object fields.
61 // If true, *object_offset contains offset of object field.
IsJSObjectFieldAccessor(Handle<Map> map,Handle<Name> name,FieldIndex * index)62 bool Accessors::IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name,
63                                         FieldIndex* index) {
64   Isolate* isolate = name->GetIsolate();
65 
66   switch (map->instance_type()) {
67     case JS_ARRAY_TYPE:
68       return CheckForName(name, isolate->factory()->length_string(),
69                           JSArray::kLengthOffset, FieldIndex::kTagged, index);
70     default:
71       if (map->instance_type() < FIRST_NONSTRING_TYPE) {
72         return CheckForName(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(Isolate * isolate,Handle<Object> receiver,Handle<JSObject> holder,Handle<Name> name,Handle<Object> value)81 Accessors::ReplaceAccessorWithDataProperty(Isolate* isolate,
82                                            Handle<Object> receiver,
83                                            Handle<JSObject> holder,
84                                            Handle<Name> name,
85                                            Handle<Object> value) {
86   LookupIterator it(receiver, name, holder,
87                     LookupIterator::OWN_SKIP_INTERCEPTOR);
88   // Skip any access checks we might hit. This accessor should never hit in a
89   // situation where the caller does not have access.
90   if (it.state() == LookupIterator::ACCESS_CHECK) {
91     CHECK(it.HasAccess());
92     it.Next();
93   }
94   DCHECK(holder.is_identical_to(it.GetHolder<JSObject>()));
95   CHECK_EQ(LookupIterator::ACCESSOR, it.state());
96   it.ReconfigureDataProperty(value, it.property_attributes());
97   return value;
98 }
99 
100 
101 //
102 // Accessors::ReconfigureToDataProperty
103 //
ReconfigureToDataProperty(v8::Local<v8::Name> key,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)104 void Accessors::ReconfigureToDataProperty(
105     v8::Local<v8::Name> key, v8::Local<v8::Value> val,
106     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
107   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
108   RuntimeCallTimerScope stats_scope(
109       isolate, RuntimeCallCounterId::kReconfigureToDataProperty);
110   HandleScope scope(isolate);
111   Handle<Object> receiver = Utils::OpenHandle(*info.This());
112   Handle<JSObject> holder =
113       Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
114   Handle<Name> name = Utils::OpenHandle(*key);
115   Handle<Object> value = Utils::OpenHandle(*val);
116   MaybeHandle<Object> result = Accessors::ReplaceAccessorWithDataProperty(
117       isolate, receiver, holder, name, value);
118   if (result.is_null()) {
119     isolate->OptionalRescheduleException(false);
120   } else {
121     info.GetReturnValue().Set(true);
122   }
123 }
124 
125 
126 //
127 // Accessors::ArgumentsIterator
128 //
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 //
147 // Accessors::ArrayLength
148 //
149 
150 
ArrayLengthGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)151 void Accessors::ArrayLengthGetter(
152     v8::Local<v8::Name> name,
153     const v8::PropertyCallbackInfo<v8::Value>& info) {
154   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
155   RuntimeCallTimerScope timer(isolate,
156                               RuntimeCallCounterId::kArrayLengthGetter);
157   DisallowHeapAllocation no_allocation;
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   RuntimeCallTimerScope timer(isolate,
169                               RuntimeCallCounterId::kArrayLengthSetter);
170   HandleScope scope(isolate);
171 
172   DCHECK(Utils::OpenHandle(*name)->SameValue(isolate->heap()->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->GetExport(Handle<String>::cast(Utils::OpenHandle(*name)))
241            .ToHandle(&result)) {
242     isolate->OptionalRescheduleException(false);
243   } else {
244     info.GetReturnValue().Set(Utils::ToLocal(result));
245   }
246 }
247 
ModuleNamespaceEntrySetter(v8::Local<v8::Name> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)248 void Accessors::ModuleNamespaceEntrySetter(
249     v8::Local<v8::Name> name, v8::Local<v8::Value> val,
250     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
251   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
252   HandleScope scope(isolate);
253   Factory* factory = isolate->factory();
254   Handle<JSModuleNamespace> holder =
255       Handle<JSModuleNamespace>::cast(Utils::OpenHandle(*info.Holder()));
256 
257   if (info.ShouldThrowOnError()) {
258     isolate->Throw(*factory->NewTypeError(
259         MessageTemplate::kStrictReadOnlyProperty, Utils::OpenHandle(*name),
260         i::Object::TypeOf(isolate, holder), holder));
261     isolate->OptionalRescheduleException(false);
262   } else {
263     info.GetReturnValue().Set(false);
264   }
265 }
266 
MakeModuleNamespaceEntryInfo(Isolate * isolate,Handle<String> name)267 Handle<AccessorInfo> Accessors::MakeModuleNamespaceEntryInfo(
268     Isolate* isolate, Handle<String> name) {
269   return MakeAccessor(isolate, name, &ModuleNamespaceEntryGetter,
270                       &ModuleNamespaceEntrySetter);
271 }
272 
273 
274 //
275 // Accessors::StringLength
276 //
277 
StringLengthGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)278 void Accessors::StringLengthGetter(
279     v8::Local<v8::Name> name,
280     const v8::PropertyCallbackInfo<v8::Value>& info) {
281   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
282   RuntimeCallTimerScope timer(isolate,
283                               RuntimeCallCounterId::kStringLengthGetter);
284   DisallowHeapAllocation no_allocation;
285   HandleScope scope(isolate);
286 
287   // We have a slight impedance mismatch between the external API and the way we
288   // use callbacks internally: Externally, callbacks can only be used with
289   // v8::Object, but internally we have callbacks on entities which are higher
290   // in the hierarchy, in this case for String values.
291 
292   Object* value = *Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
293   if (!value->IsString()) {
294     // Not a string value. That means that we either got a String wrapper or
295     // a Value with a String wrapper in its prototype chain.
296     value = JSValue::cast(*Utils::OpenHandle(*info.Holder()))->value();
297   }
298   Object* result = Smi::FromInt(String::cast(value)->length());
299   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(result, isolate)));
300 }
301 
MakeStringLengthInfo(Isolate * isolate)302 Handle<AccessorInfo> Accessors::MakeStringLengthInfo(Isolate* isolate) {
303   return MakeAccessor(isolate, isolate->factory()->length_string(),
304                       &StringLengthGetter, nullptr);
305 }
306 
307 //
308 // Accessors::ScriptColumnOffset
309 //
310 
311 
ScriptColumnOffsetGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)312 void Accessors::ScriptColumnOffsetGetter(
313     v8::Local<v8::Name> name,
314     const v8::PropertyCallbackInfo<v8::Value>& info) {
315   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
316   DisallowHeapAllocation no_allocation;
317   HandleScope scope(isolate);
318   Object* object = *Utils::OpenHandle(*info.Holder());
319   Object* res = Smi::FromInt(
320       Script::cast(JSValue::cast(object)->value())->column_offset());
321   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
322 }
323 
MakeScriptColumnOffsetInfo(Isolate * isolate)324 Handle<AccessorInfo> Accessors::MakeScriptColumnOffsetInfo(Isolate* isolate) {
325   Handle<String> name(isolate->factory()->InternalizeOneByteString(
326       STATIC_CHAR_VECTOR("column_offset")));
327   return MakeAccessor(isolate, name, &ScriptColumnOffsetGetter, nullptr);
328 }
329 
330 
331 //
332 // Accessors::ScriptId
333 //
334 
335 
ScriptIdGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)336 void Accessors::ScriptIdGetter(
337     v8::Local<v8::Name> name,
338     const v8::PropertyCallbackInfo<v8::Value>& info) {
339   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
340   DisallowHeapAllocation no_allocation;
341   HandleScope scope(isolate);
342   Object* object = *Utils::OpenHandle(*info.Holder());
343   Object* id = Smi::FromInt(Script::cast(JSValue::cast(object)->value())->id());
344   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(id, isolate)));
345 }
346 
MakeScriptIdInfo(Isolate * isolate)347 Handle<AccessorInfo> Accessors::MakeScriptIdInfo(Isolate* isolate) {
348   Handle<String> name(
349       isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("id")));
350   return MakeAccessor(isolate, name, &ScriptIdGetter, nullptr);
351 }
352 
353 
354 //
355 // Accessors::ScriptName
356 //
357 
358 
ScriptNameGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)359 void Accessors::ScriptNameGetter(
360     v8::Local<v8::Name> name,
361     const v8::PropertyCallbackInfo<v8::Value>& info) {
362   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
363   DisallowHeapAllocation no_allocation;
364   HandleScope scope(isolate);
365   Object* object = *Utils::OpenHandle(*info.Holder());
366   Object* source = Script::cast(JSValue::cast(object)->value())->name();
367   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate)));
368 }
369 
MakeScriptNameInfo(Isolate * isolate)370 Handle<AccessorInfo> Accessors::MakeScriptNameInfo(Isolate* isolate) {
371   return MakeAccessor(isolate, isolate->factory()->name_string(),
372                       &ScriptNameGetter, nullptr);
373 }
374 
375 
376 //
377 // Accessors::ScriptSource
378 //
379 
380 
ScriptSourceGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)381 void Accessors::ScriptSourceGetter(
382     v8::Local<v8::Name> name,
383     const v8::PropertyCallbackInfo<v8::Value>& info) {
384   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
385   DisallowHeapAllocation no_allocation;
386   HandleScope scope(isolate);
387   Object* object = *Utils::OpenHandle(*info.Holder());
388   Object* source = Script::cast(JSValue::cast(object)->value())->source();
389   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(source, isolate)));
390 }
391 
MakeScriptSourceInfo(Isolate * isolate)392 Handle<AccessorInfo> Accessors::MakeScriptSourceInfo(Isolate* isolate) {
393   return MakeAccessor(isolate, isolate->factory()->source_string(),
394                       &ScriptSourceGetter, nullptr);
395 }
396 
397 
398 //
399 // Accessors::ScriptLineOffset
400 //
401 
402 
ScriptLineOffsetGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)403 void Accessors::ScriptLineOffsetGetter(
404     v8::Local<v8::Name> name,
405     const v8::PropertyCallbackInfo<v8::Value>& info) {
406   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
407   DisallowHeapAllocation no_allocation;
408   HandleScope scope(isolate);
409   Object* object = *Utils::OpenHandle(*info.Holder());
410   Object* res =
411       Smi::FromInt(Script::cast(JSValue::cast(object)->value())->line_offset());
412   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
413 }
414 
MakeScriptLineOffsetInfo(Isolate * isolate)415 Handle<AccessorInfo> Accessors::MakeScriptLineOffsetInfo(Isolate* isolate) {
416   Handle<String> name(isolate->factory()->InternalizeOneByteString(
417       STATIC_CHAR_VECTOR("line_offset")));
418   return MakeAccessor(isolate, name, &ScriptLineOffsetGetter, nullptr);
419 }
420 
421 
422 //
423 // Accessors::ScriptType
424 //
425 
426 
ScriptTypeGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)427 void Accessors::ScriptTypeGetter(
428     v8::Local<v8::Name> name,
429     const v8::PropertyCallbackInfo<v8::Value>& info) {
430   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
431   DisallowHeapAllocation no_allocation;
432   HandleScope scope(isolate);
433   Object* object = *Utils::OpenHandle(*info.Holder());
434   Object* res =
435       Smi::FromInt(Script::cast(JSValue::cast(object)->value())->type());
436   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
437 }
438 
MakeScriptTypeInfo(Isolate * isolate)439 Handle<AccessorInfo> Accessors::MakeScriptTypeInfo(Isolate* isolate) {
440   Handle<String> name(
441       isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("type")));
442   return MakeAccessor(isolate, name, &ScriptTypeGetter, nullptr);
443 }
444 
445 
446 //
447 // Accessors::ScriptCompilationType
448 //
449 
450 
ScriptCompilationTypeGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)451 void Accessors::ScriptCompilationTypeGetter(
452     v8::Local<v8::Name> name,
453     const v8::PropertyCallbackInfo<v8::Value>& info) {
454   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
455   DisallowHeapAllocation no_allocation;
456   HandleScope scope(isolate);
457   Object* object = *Utils::OpenHandle(*info.Holder());
458   Object* res = Smi::FromInt(
459       Script::cast(JSValue::cast(object)->value())->compilation_type());
460   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
461 }
462 
MakeScriptCompilationTypeInfo(Isolate * isolate)463 Handle<AccessorInfo> Accessors::MakeScriptCompilationTypeInfo(
464     Isolate* isolate) {
465   Handle<String> name(isolate->factory()->InternalizeOneByteString(
466       STATIC_CHAR_VECTOR("compilation_type")));
467   return MakeAccessor(isolate, name, &ScriptCompilationTypeGetter, nullptr);
468 }
469 
470 
471 //
472 // Accessors::ScriptSourceUrl
473 //
474 
475 
ScriptSourceUrlGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)476 void Accessors::ScriptSourceUrlGetter(
477     v8::Local<v8::Name> name,
478     const v8::PropertyCallbackInfo<v8::Value>& info) {
479   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
480   DisallowHeapAllocation no_allocation;
481   HandleScope scope(isolate);
482   Object* object = *Utils::OpenHandle(*info.Holder());
483   Object* url = Script::cast(JSValue::cast(object)->value())->source_url();
484   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(url, isolate)));
485 }
486 
MakeScriptSourceUrlInfo(Isolate * isolate)487 Handle<AccessorInfo> Accessors::MakeScriptSourceUrlInfo(Isolate* isolate) {
488   Handle<String> name(isolate->factory()->InternalizeOneByteString(
489       STATIC_CHAR_VECTOR("source_url")));
490   return MakeAccessor(isolate, name, &ScriptSourceUrlGetter, nullptr);
491 }
492 
493 
494 //
495 // Accessors::ScriptSourceMappingUrl
496 //
497 
498 
ScriptSourceMappingUrlGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)499 void Accessors::ScriptSourceMappingUrlGetter(
500     v8::Local<v8::Name> name,
501     const v8::PropertyCallbackInfo<v8::Value>& info) {
502   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
503   DisallowHeapAllocation no_allocation;
504   HandleScope scope(isolate);
505   Object* object = *Utils::OpenHandle(*info.Holder());
506   Object* url =
507       Script::cast(JSValue::cast(object)->value())->source_mapping_url();
508   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(url, isolate)));
509 }
510 
MakeScriptSourceMappingUrlInfo(Isolate * isolate)511 Handle<AccessorInfo> Accessors::MakeScriptSourceMappingUrlInfo(
512     Isolate* isolate) {
513   Handle<String> name(isolate->factory()->InternalizeOneByteString(
514       STATIC_CHAR_VECTOR("source_mapping_url")));
515   return MakeAccessor(isolate, name, &ScriptSourceMappingUrlGetter, nullptr);
516 }
517 
518 
519 //
520 // Accessors::ScriptGetContextData
521 //
522 
523 
ScriptContextDataGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)524 void Accessors::ScriptContextDataGetter(
525     v8::Local<v8::Name> name,
526     const v8::PropertyCallbackInfo<v8::Value>& info) {
527   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
528   DisallowHeapAllocation no_allocation;
529   HandleScope scope(isolate);
530   Object* object = *Utils::OpenHandle(*info.Holder());
531   Object* res = Script::cast(JSValue::cast(object)->value())->context_data();
532   info.GetReturnValue().Set(Utils::ToLocal(Handle<Object>(res, isolate)));
533 }
534 
MakeScriptContextDataInfo(Isolate * isolate)535 Handle<AccessorInfo> Accessors::MakeScriptContextDataInfo(Isolate* isolate) {
536   Handle<String> name(isolate->factory()->InternalizeOneByteString(
537       STATIC_CHAR_VECTOR("context_data")));
538   return MakeAccessor(isolate, name, &ScriptContextDataGetter, nullptr);
539 }
540 
541 
542 //
543 // Accessors::ScriptGetEvalFromScript
544 //
545 
546 
ScriptEvalFromScriptGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)547 void Accessors::ScriptEvalFromScriptGetter(
548     v8::Local<v8::Name> name,
549     const v8::PropertyCallbackInfo<v8::Value>& info) {
550   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
551   HandleScope scope(isolate);
552   Handle<Object> object = Utils::OpenHandle(*info.Holder());
553   Handle<Script> script(
554       Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
555   Handle<Object> result = isolate->factory()->undefined_value();
556   if (script->has_eval_from_shared()) {
557     Handle<SharedFunctionInfo> eval_from_shared(script->eval_from_shared());
558     if (eval_from_shared->script()->IsScript()) {
559       Handle<Script> eval_from_script(Script::cast(eval_from_shared->script()));
560       result = Script::GetWrapper(eval_from_script);
561     }
562   }
563 
564   info.GetReturnValue().Set(Utils::ToLocal(result));
565 }
566 
MakeScriptEvalFromScriptInfo(Isolate * isolate)567 Handle<AccessorInfo> Accessors::MakeScriptEvalFromScriptInfo(Isolate* isolate) {
568   Handle<String> name(isolate->factory()->InternalizeOneByteString(
569       STATIC_CHAR_VECTOR("eval_from_script")));
570   return MakeAccessor(isolate, name, &ScriptEvalFromScriptGetter, nullptr);
571 }
572 
573 
574 //
575 // Accessors::ScriptGetEvalFromScriptPosition
576 //
577 
578 
ScriptEvalFromScriptPositionGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)579 void Accessors::ScriptEvalFromScriptPositionGetter(
580     v8::Local<v8::Name> name,
581     const v8::PropertyCallbackInfo<v8::Value>& info) {
582   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
583   HandleScope scope(isolate);
584   Handle<Object> object = Utils::OpenHandle(*info.Holder());
585   Handle<Script> script(
586       Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
587   Handle<Object> result = isolate->factory()->undefined_value();
588   if (script->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
589     result = Handle<Object>(Smi::FromInt(script->GetEvalPosition()), isolate);
590   }
591   info.GetReturnValue().Set(Utils::ToLocal(result));
592 }
593 
MakeScriptEvalFromScriptPositionInfo(Isolate * isolate)594 Handle<AccessorInfo> Accessors::MakeScriptEvalFromScriptPositionInfo(
595     Isolate* isolate) {
596   Handle<String> name(isolate->factory()->InternalizeOneByteString(
597       STATIC_CHAR_VECTOR("eval_from_script_position")));
598   return MakeAccessor(isolate, name, &ScriptEvalFromScriptPositionGetter,
599                       nullptr);
600 }
601 
602 
603 //
604 // Accessors::ScriptGetEvalFromFunctionName
605 //
606 
607 
ScriptEvalFromFunctionNameGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)608 void Accessors::ScriptEvalFromFunctionNameGetter(
609     v8::Local<v8::Name> name,
610     const v8::PropertyCallbackInfo<v8::Value>& info) {
611   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
612   HandleScope scope(isolate);
613   Handle<Object> object = Utils::OpenHandle(*info.Holder());
614   Handle<Script> script(
615       Script::cast(Handle<JSValue>::cast(object)->value()), isolate);
616   Handle<Object> result = isolate->factory()->undefined_value();
617   if (script->has_eval_from_shared()) {
618     Handle<SharedFunctionInfo> shared(script->eval_from_shared());
619     // Find the name of the function calling eval.
620     result = Handle<Object>(shared->Name(), isolate);
621   }
622   info.GetReturnValue().Set(Utils::ToLocal(result));
623 }
624 
MakeScriptEvalFromFunctionNameInfo(Isolate * isolate)625 Handle<AccessorInfo> Accessors::MakeScriptEvalFromFunctionNameInfo(
626     Isolate* isolate) {
627   Handle<String> name(isolate->factory()->InternalizeOneByteString(
628       STATIC_CHAR_VECTOR("eval_from_function_name")));
629   return MakeAccessor(isolate, name, &ScriptEvalFromFunctionNameGetter,
630                       nullptr);
631 }
632 
633 
634 //
635 // Accessors::FunctionPrototype
636 //
637 
GetFunctionPrototype(Isolate * isolate,Handle<JSFunction> function)638 static Handle<Object> GetFunctionPrototype(Isolate* isolate,
639                                            Handle<JSFunction> function) {
640   if (!function->has_prototype()) {
641     Handle<Object> proto = isolate->factory()->NewFunctionPrototype(function);
642     JSFunction::SetPrototype(function, proto);
643   }
644   return Handle<Object>(function->prototype(), isolate);
645 }
646 
FunctionPrototypeGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)647 void Accessors::FunctionPrototypeGetter(
648     v8::Local<v8::Name> name,
649     const v8::PropertyCallbackInfo<v8::Value>& info) {
650   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
651   RuntimeCallTimerScope timer(isolate,
652                               RuntimeCallCounterId::kFunctionPrototypeGetter);
653   HandleScope scope(isolate);
654   Handle<JSFunction> function =
655       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
656   Handle<Object> result = GetFunctionPrototype(isolate, function);
657   info.GetReturnValue().Set(Utils::ToLocal(result));
658 }
659 
FunctionPrototypeSetter(v8::Local<v8::Name> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)660 void Accessors::FunctionPrototypeSetter(
661     v8::Local<v8::Name> name, v8::Local<v8::Value> val,
662     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
663   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
664   RuntimeCallTimerScope timer(isolate,
665                               RuntimeCallCounterId::kFunctionPrototypeSetter);
666   HandleScope scope(isolate);
667   Handle<Object> value = Utils::OpenHandle(*val);
668   Handle<JSFunction> object =
669       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
670   JSFunction::SetPrototype(object, value);
671   info.GetReturnValue().Set(true);
672 }
673 
MakeFunctionPrototypeInfo(Isolate * isolate)674 Handle<AccessorInfo> Accessors::MakeFunctionPrototypeInfo(Isolate* isolate) {
675   return MakeAccessor(isolate, isolate->factory()->prototype_string(),
676                       &FunctionPrototypeGetter, &FunctionPrototypeSetter);
677 }
678 
679 
680 //
681 // Accessors::FunctionLength
682 //
683 
684 
FunctionLengthGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)685 void Accessors::FunctionLengthGetter(
686     v8::Local<v8::Name> name,
687     const v8::PropertyCallbackInfo<v8::Value>& info) {
688   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
689   RuntimeCallTimerScope timer(isolate,
690                               RuntimeCallCounterId::kFunctionLengthGetter);
691   HandleScope scope(isolate);
692   Handle<JSFunction> function =
693       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
694   int length = 0;
695   if (!JSFunction::GetLength(isolate, function).To(&length)) {
696     isolate->OptionalRescheduleException(false);
697   }
698   Handle<Object> result(Smi::FromInt(length), isolate);
699   info.GetReturnValue().Set(Utils::ToLocal(result));
700 }
701 
MakeFunctionLengthInfo(Isolate * isolate)702 Handle<AccessorInfo> Accessors::MakeFunctionLengthInfo(Isolate* isolate) {
703   return MakeAccessor(isolate, isolate->factory()->length_string(),
704                       &FunctionLengthGetter, &ReconfigureToDataProperty);
705 }
706 
707 
708 //
709 // Accessors::FunctionName
710 //
711 
712 
FunctionNameGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)713 void Accessors::FunctionNameGetter(
714     v8::Local<v8::Name> name,
715     const v8::PropertyCallbackInfo<v8::Value>& info) {
716   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
717   HandleScope scope(isolate);
718   Handle<JSFunction> function =
719       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
720   Handle<Object> result = JSFunction::GetName(isolate, function);
721   info.GetReturnValue().Set(Utils::ToLocal(result));
722 }
723 
MakeFunctionNameInfo(Isolate * isolate)724 Handle<AccessorInfo> Accessors::MakeFunctionNameInfo(Isolate* isolate) {
725   return MakeAccessor(isolate, isolate->factory()->name_string(),
726                       &FunctionNameGetter, &ReconfigureToDataProperty);
727 }
728 
729 
730 //
731 // Accessors::FunctionArguments
732 //
733 
734 namespace {
735 
ArgumentsForInlinedFunction(JavaScriptFrame * frame,int inlined_frame_index)736 Handle<JSObject> ArgumentsForInlinedFunction(JavaScriptFrame* frame,
737                                              int inlined_frame_index) {
738   Isolate* isolate = frame->isolate();
739   Factory* factory = isolate->factory();
740 
741   TranslatedState translated_values(frame);
742   translated_values.Prepare(frame->fp());
743 
744   int argument_count = 0;
745   TranslatedFrame* translated_frame =
746       translated_values.GetArgumentsInfoFromJSFrameIndex(inlined_frame_index,
747                                                          &argument_count);
748   TranslatedFrame::iterator iter = translated_frame->begin();
749 
750   // Materialize the function.
751   bool should_deoptimize = iter->IsMaterializedObject();
752   Handle<JSFunction> function = Handle<JSFunction>::cast(iter->GetValue());
753   iter++;
754 
755   // Skip the receiver.
756   iter++;
757   argument_count--;
758 
759   Handle<JSObject> arguments =
760       factory->NewArgumentsObject(function, argument_count);
761   Handle<FixedArray> array = factory->NewFixedArray(argument_count);
762   for (int i = 0; i < argument_count; ++i) {
763     // If we materialize any object, we should deoptimize the frame because we
764     // might alias an object that was eliminated by escape analysis.
765     should_deoptimize = should_deoptimize || iter->IsMaterializedObject();
766     Handle<Object> value = iter->GetValue();
767     array->set(i, *value);
768     iter++;
769   }
770   arguments->set_elements(*array);
771 
772   if (should_deoptimize) {
773     translated_values.StoreMaterializedValuesAndDeopt(frame);
774   }
775 
776   // Return the freshly allocated arguments object.
777   return arguments;
778 }
779 
FindFunctionInFrame(JavaScriptFrame * frame,Handle<JSFunction> function)780 int FindFunctionInFrame(JavaScriptFrame* frame, Handle<JSFunction> function) {
781   std::vector<FrameSummary> frames;
782   frame->Summarize(&frames);
783   for (size_t i = frames.size(); i != 0; i--) {
784     if (*frames[i - 1].AsJavaScript().function() == *function) {
785       return static_cast<int>(i) - 1;
786     }
787   }
788   return -1;
789 }
790 
GetFrameArguments(Isolate * isolate,JavaScriptFrameIterator * it,int function_index)791 Handle<JSObject> GetFrameArguments(Isolate* isolate,
792                                    JavaScriptFrameIterator* it,
793                                    int function_index) {
794   JavaScriptFrame* frame = it->frame();
795 
796   if (function_index > 0) {
797     // The function in question was inlined.  Inlined functions have the
798     // correct number of arguments and no allocated arguments object, so
799     // we can construct a fresh one by interpreting the function's
800     // deoptimization input data.
801     return ArgumentsForInlinedFunction(frame, function_index);
802   }
803 
804   // Find the frame that holds the actual arguments passed to the function.
805   if (it->frame()->has_adapted_arguments()) {
806     it->AdvanceOneFrame();
807     DCHECK(it->frame()->is_arguments_adaptor());
808   }
809   frame = it->frame();
810 
811   // Get the number of arguments and construct an arguments object
812   // mirror for the right frame and the underlying function.
813   const int length = frame->ComputeParametersCount();
814   Handle<JSFunction> function(frame->function(), isolate);
815   Handle<JSObject> arguments =
816       isolate->factory()->NewArgumentsObject(function, length);
817   Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
818 
819   // Copy the parameters to the arguments object.
820   DCHECK(array->length() == length);
821   for (int i = 0; i < length; i++) {
822     Object* value = frame->GetParameter(i);
823     if (value->IsTheHole(isolate)) {
824       // Generators currently use holes as dummy arguments when resuming.  We
825       // must not leak those.
826       DCHECK(IsResumableFunction(function->shared()->kind()));
827       value = isolate->heap()->undefined_value();
828     }
829     array->set(i, value);
830   }
831   arguments->set_elements(*array);
832 
833   // Return the freshly allocated arguments object.
834   return arguments;
835 }
836 
837 }  // namespace
838 
FunctionGetArguments(JavaScriptFrame * frame,int inlined_jsframe_index)839 Handle<JSObject> Accessors::FunctionGetArguments(JavaScriptFrame* frame,
840                                                  int inlined_jsframe_index) {
841   Isolate* isolate = frame->isolate();
842   Address requested_frame_fp = frame->fp();
843   // Forward a frame iterator to the requested frame. This is needed because we
844   // potentially need for advance it to the arguments adaptor frame later.
845   for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
846     if (it.frame()->fp() != requested_frame_fp) continue;
847     return GetFrameArguments(isolate, &it, inlined_jsframe_index);
848   }
849   UNREACHABLE();  // Requested frame not found.
850   return Handle<JSObject>();
851 }
852 
853 
FunctionArgumentsGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)854 void Accessors::FunctionArgumentsGetter(
855     v8::Local<v8::Name> name,
856     const v8::PropertyCallbackInfo<v8::Value>& info) {
857   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
858   HandleScope scope(isolate);
859   Handle<JSFunction> function =
860       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
861   Handle<Object> result = isolate->factory()->null_value();
862   if (!function->shared()->native()) {
863     // Find the top invocation of the function by traversing frames.
864     for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
865       JavaScriptFrame* frame = it.frame();
866       int function_index = FindFunctionInFrame(frame, function);
867       if (function_index >= 0) {
868         result = GetFrameArguments(isolate, &it, function_index);
869         break;
870       }
871     }
872   }
873   info.GetReturnValue().Set(Utils::ToLocal(result));
874 }
875 
MakeFunctionArgumentsInfo(Isolate * isolate)876 Handle<AccessorInfo> Accessors::MakeFunctionArgumentsInfo(Isolate* isolate) {
877   return MakeAccessor(isolate, isolate->factory()->arguments_string(),
878                       &FunctionArgumentsGetter, nullptr);
879 }
880 
881 
882 //
883 // Accessors::FunctionCaller
884 //
885 
886 
AllowAccessToFunction(Context * current_context,JSFunction * function)887 static inline bool AllowAccessToFunction(Context* current_context,
888                                          JSFunction* function) {
889   return current_context->HasSameSecurityTokenAs(function->context());
890 }
891 
892 
893 class FrameFunctionIterator {
894  public:
FrameFunctionIterator(Isolate * isolate)895   explicit FrameFunctionIterator(Isolate* isolate)
896       : isolate_(isolate), frame_iterator_(isolate), inlined_frame_index_(-1) {
897     GetFrames();
898   }
899 
900   // Iterate through functions until the first occurrence of 'function'.
901   // Returns true if one is found, and false if the iterator ends before.
Find(Handle<JSFunction> function)902   bool Find(Handle<JSFunction> function) {
903     do {
904       if (!next().ToHandle(&function_)) return false;
905     } while (!function_.is_identical_to(function));
906     return true;
907   }
908 
909   // Iterate through functions until the next non-toplevel one is found.
910   // Returns true if one is found, and false if the iterator ends before.
FindNextNonTopLevel()911   bool FindNextNonTopLevel() {
912     do {
913       if (!next().ToHandle(&function_)) return false;
914     } while (function_->shared()->is_toplevel());
915     return true;
916   }
917 
918   // Iterate through function until the first native or user-provided function
919   // is found. Functions not defined in user-provided scripts are not visible
920   // unless directly exposed, in which case the native flag is set on them.
921   // Returns true if one is found, and false if the iterator ends before.
FindFirstNativeOrUserJavaScript()922   bool FindFirstNativeOrUserJavaScript() {
923     while (!function_->shared()->native() &&
924            !function_->shared()->IsUserJavaScript()) {
925       if (!next().ToHandle(&function_)) return false;
926     }
927     return true;
928   }
929 
930   // In case of inlined frames the function could have been materialized from
931   // deoptimization information. If that is the case we need to make sure that
932   // subsequent call will see the same function, since we are about to hand out
933   // the value to JavaScript. Make sure to store the materialized value and
934   // trigger a deoptimization of the underlying frame.
MaterializeFunction()935   Handle<JSFunction> MaterializeFunction() {
936     if (inlined_frame_index_ == 0) return function_;
937 
938     JavaScriptFrame* frame = frame_iterator_.frame();
939     TranslatedState translated_values(frame);
940     translated_values.Prepare(frame->fp());
941 
942     TranslatedFrame* translated_frame =
943         translated_values.GetFrameFromJSFrameIndex(inlined_frame_index_);
944     TranslatedFrame::iterator iter = translated_frame->begin();
945 
946     // First value is the function.
947     bool should_deoptimize = iter->IsMaterializedObject();
948     Handle<Object> value = iter->GetValue();
949     if (should_deoptimize) {
950       translated_values.StoreMaterializedValuesAndDeopt(frame);
951     }
952 
953     return Handle<JSFunction>::cast(value);
954   }
955 
956  private:
next()957   MaybeHandle<JSFunction> next() {
958     while (true) {
959       if (inlined_frame_index_ <= 0) {
960         if (!frame_iterator_.done()) {
961           frame_iterator_.Advance();
962           frames_.clear();
963           inlined_frame_index_ = -1;
964           GetFrames();
965         }
966         if (inlined_frame_index_ == -1) return MaybeHandle<JSFunction>();
967       }
968 
969       --inlined_frame_index_;
970       Handle<JSFunction> next_function =
971           frames_[inlined_frame_index_].AsJavaScript().function();
972       // Skip functions from other origins.
973       if (!AllowAccessToFunction(isolate_->context(), *next_function)) continue;
974       return next_function;
975     }
976   }
GetFrames()977   void GetFrames() {
978     DCHECK_EQ(-1, inlined_frame_index_);
979     if (frame_iterator_.done()) return;
980     JavaScriptFrame* frame = frame_iterator_.frame();
981     frame->Summarize(&frames_);
982     inlined_frame_index_ = static_cast<int>(frames_.size());
983     DCHECK_LT(0, inlined_frame_index_);
984   }
985   Isolate* isolate_;
986   Handle<JSFunction> function_;
987   JavaScriptFrameIterator frame_iterator_;
988   std::vector<FrameSummary> frames_;
989   int inlined_frame_index_;
990 };
991 
992 
FindCaller(Isolate * isolate,Handle<JSFunction> function)993 MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
994                                    Handle<JSFunction> function) {
995   FrameFunctionIterator it(isolate);
996   if (function->shared()->native()) {
997     return MaybeHandle<JSFunction>();
998   }
999   // Find the function from the frames. Return null in case no frame
1000   // corresponding to the given function was found.
1001   if (!it.Find(function)) {
1002     return MaybeHandle<JSFunction>();
1003   }
1004   // Find previously called non-toplevel function.
1005   if (!it.FindNextNonTopLevel()) {
1006     return MaybeHandle<JSFunction>();
1007   }
1008   // Find the first user-land JavaScript function (or the entry point into
1009   // native JavaScript builtins in case such a builtin was the caller).
1010   if (!it.FindFirstNativeOrUserJavaScript()) {
1011     return MaybeHandle<JSFunction>();
1012   }
1013 
1014   // Materialize the function that the iterator is currently sitting on. Note
1015   // that this might trigger deoptimization in case the function was actually
1016   // materialized. Identity of the function must be preserved because we are
1017   // going to return it to JavaScript after this point.
1018   Handle<JSFunction> caller = it.MaterializeFunction();
1019 
1020   // Censor if the caller is not a sloppy mode function.
1021   // Change from ES5, which used to throw, see:
1022   // https://bugs.ecmascript.org/show_bug.cgi?id=310
1023   if (is_strict(caller->shared()->language_mode())) {
1024     return MaybeHandle<JSFunction>();
1025   }
1026   // Don't return caller from another security context.
1027   if (!AllowAccessToFunction(isolate->context(), *caller)) {
1028     return MaybeHandle<JSFunction>();
1029   }
1030   return caller;
1031 }
1032 
1033 
FunctionCallerGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)1034 void Accessors::FunctionCallerGetter(
1035     v8::Local<v8::Name> name,
1036     const v8::PropertyCallbackInfo<v8::Value>& info) {
1037   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
1038   HandleScope scope(isolate);
1039   Handle<JSFunction> function =
1040       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
1041   Handle<Object> result;
1042   MaybeHandle<JSFunction> maybe_caller;
1043   maybe_caller = FindCaller(isolate, function);
1044   Handle<JSFunction> caller;
1045   if (maybe_caller.ToHandle(&caller)) {
1046     result = caller;
1047   } else {
1048     result = isolate->factory()->null_value();
1049   }
1050   info.GetReturnValue().Set(Utils::ToLocal(result));
1051 }
1052 
MakeFunctionCallerInfo(Isolate * isolate)1053 Handle<AccessorInfo> Accessors::MakeFunctionCallerInfo(Isolate* isolate) {
1054   return MakeAccessor(isolate, isolate->factory()->caller_string(),
1055                       &FunctionCallerGetter, nullptr);
1056 }
1057 
1058 
1059 //
1060 // Accessors::BoundFunctionLength
1061 //
1062 
BoundFunctionLengthGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)1063 void Accessors::BoundFunctionLengthGetter(
1064     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1065   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
1066   RuntimeCallTimerScope timer(isolate,
1067                               RuntimeCallCounterId::kBoundFunctionLengthGetter);
1068   HandleScope scope(isolate);
1069   Handle<JSBoundFunction> function =
1070       Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
1071 
1072   int length = 0;
1073   if (!JSBoundFunction::GetLength(isolate, function).To(&length)) {
1074     isolate->OptionalRescheduleException(false);
1075     return;
1076   }
1077   Handle<Object> result(Smi::FromInt(length), isolate);
1078   info.GetReturnValue().Set(Utils::ToLocal(result));
1079 }
1080 
MakeBoundFunctionLengthInfo(Isolate * isolate)1081 Handle<AccessorInfo> Accessors::MakeBoundFunctionLengthInfo(Isolate* isolate) {
1082   return MakeAccessor(isolate, isolate->factory()->length_string(),
1083                       &BoundFunctionLengthGetter, &ReconfigureToDataProperty);
1084 }
1085 
1086 //
1087 // Accessors::BoundFunctionName
1088 //
1089 
BoundFunctionNameGetter(v8::Local<v8::Name> name,const v8::PropertyCallbackInfo<v8::Value> & info)1090 void Accessors::BoundFunctionNameGetter(
1091     v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1092   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
1093   RuntimeCallTimerScope timer(isolate,
1094                               RuntimeCallCounterId::kBoundFunctionNameGetter);
1095   HandleScope scope(isolate);
1096   Handle<JSBoundFunction> function =
1097       Handle<JSBoundFunction>::cast(Utils::OpenHandle(*info.Holder()));
1098   Handle<Object> result;
1099   if (!JSBoundFunction::GetName(isolate, function).ToHandle(&result)) {
1100     isolate->OptionalRescheduleException(false);
1101     return;
1102   }
1103   info.GetReturnValue().Set(Utils::ToLocal(result));
1104 }
1105 
MakeBoundFunctionNameInfo(Isolate * isolate)1106 Handle<AccessorInfo> Accessors::MakeBoundFunctionNameInfo(Isolate* isolate) {
1107   return MakeAccessor(isolate, isolate->factory()->name_string(),
1108                       &BoundFunctionNameGetter, &ReconfigureToDataProperty);
1109 }
1110 
1111 //
1112 // Accessors::ErrorStack
1113 //
1114 
1115 namespace {
1116 
ClearInternalStackTrace(Isolate * isolate,Handle<JSObject> error)1117 MaybeHandle<JSReceiver> ClearInternalStackTrace(Isolate* isolate,
1118                                                 Handle<JSObject> error) {
1119   RETURN_ON_EXCEPTION(
1120       isolate,
1121       JSReceiver::SetProperty(error, isolate->factory()->stack_trace_symbol(),
1122                               isolate->factory()->undefined_value(),
1123                               LanguageMode::kStrict),
1124       JSReceiver);
1125   return error;
1126 }
1127 
IsAccessor(Handle<Object> receiver,Handle<Name> name,Handle<JSObject> holder)1128 bool IsAccessor(Handle<Object> receiver, Handle<Name> name,
1129                 Handle<JSObject> holder) {
1130   LookupIterator it(receiver, name, holder,
1131                     LookupIterator::OWN_SKIP_INTERCEPTOR);
1132   // Skip any access checks we might hit. This accessor should never hit in a
1133   // situation where the caller does not have access.
1134   if (it.state() == LookupIterator::ACCESS_CHECK) {
1135     CHECK(it.HasAccess());
1136     it.Next();
1137   }
1138   return (it.state() == LookupIterator::ACCESSOR);
1139 }
1140 
1141 }  // namespace
1142 
ErrorStackGetter(v8::Local<v8::Name> key,const v8::PropertyCallbackInfo<v8::Value> & info)1143 void Accessors::ErrorStackGetter(
1144     v8::Local<v8::Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
1145   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
1146   HandleScope scope(isolate);
1147   Handle<JSObject> holder =
1148       Handle<JSObject>::cast(Utils::OpenHandle(*info.Holder()));
1149 
1150   // Retrieve the structured stack trace.
1151 
1152   Handle<Object> stack_trace;
1153   Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
1154   MaybeHandle<Object> maybe_stack_trace =
1155       JSObject::GetProperty(holder, stack_trace_symbol);
1156   if (!maybe_stack_trace.ToHandle(&stack_trace) ||
1157       stack_trace->IsUndefined(isolate)) {
1158     Handle<Object> result = isolate->factory()->undefined_value();
1159     info.GetReturnValue().Set(Utils::ToLocal(result));
1160     return;
1161   }
1162 
1163   // Format it, clear the internal structured trace and reconfigure as a data
1164   // property.
1165 
1166   Handle<Object> formatted_stack_trace;
1167   if (!ErrorUtils::FormatStackTrace(isolate, holder, stack_trace)
1168            .ToHandle(&formatted_stack_trace)) {
1169     isolate->OptionalRescheduleException(false);
1170     return;
1171   }
1172 
1173   MaybeHandle<Object> result = ClearInternalStackTrace(isolate, holder);
1174   if (result.is_null()) {
1175     isolate->OptionalRescheduleException(false);
1176     return;
1177   }
1178 
1179   // If stack is still an accessor (this could have changed in the meantime
1180   // since FormatStackTrace can execute arbitrary JS), replace it with a data
1181   // property.
1182   Handle<Object> receiver =
1183       Utils::OpenHandle(*v8::Local<v8::Value>(info.This()));
1184   Handle<Name> name = Utils::OpenHandle(*key);
1185   if (IsAccessor(receiver, name, holder)) {
1186     result = Accessors::ReplaceAccessorWithDataProperty(
1187         isolate, receiver, holder, name, formatted_stack_trace);
1188     if (result.is_null()) {
1189       isolate->OptionalRescheduleException(false);
1190       return;
1191     }
1192   } else {
1193     // The stack property has been modified in the meantime.
1194     if (!JSObject::GetProperty(holder, name).ToHandle(&formatted_stack_trace)) {
1195       isolate->OptionalRescheduleException(false);
1196       return;
1197     }
1198   }
1199 
1200   v8::Local<v8::Value> value = Utils::ToLocal(formatted_stack_trace);
1201   info.GetReturnValue().Set(value);
1202 }
1203 
ErrorStackSetter(v8::Local<v8::Name> name,v8::Local<v8::Value> val,const v8::PropertyCallbackInfo<v8::Boolean> & info)1204 void Accessors::ErrorStackSetter(
1205     v8::Local<v8::Name> name, v8::Local<v8::Value> val,
1206     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
1207   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(info.GetIsolate());
1208   HandleScope scope(isolate);
1209   Handle<JSObject> obj = Handle<JSObject>::cast(
1210       Utils::OpenHandle(*v8::Local<v8::Value>(info.This())));
1211 
1212   // Clear internal properties to avoid memory leaks.
1213   Handle<Symbol> stack_trace_symbol = isolate->factory()->stack_trace_symbol();
1214   if (JSReceiver::HasOwnProperty(obj, stack_trace_symbol).FromMaybe(false)) {
1215     ClearInternalStackTrace(isolate, obj);
1216   }
1217 
1218   Accessors::ReconfigureToDataProperty(name, val, info);
1219 }
1220 
MakeErrorStackInfo(Isolate * isolate)1221 Handle<AccessorInfo> Accessors::MakeErrorStackInfo(Isolate* isolate) {
1222   return MakeAccessor(isolate, isolate->factory()->stack_string(),
1223                       &ErrorStackGetter, &ErrorStackSetter);
1224 }
1225 
1226 }  // namespace internal
1227 }  // namespace v8
1228