1// Copyright 2021 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/objects/templates.h"
6
7#include "src/api/api-inl.h"
8#include "src/execution/isolate.h"
9#include "src/heap/factory.h"
10#include "src/objects/function-kind.h"
11#include "src/objects/instance-type-inl.h"
12#include "src/objects/js-function-inl.h"
13#include "src/objects/map-inl.h"
14#include "src/objects/name-inl.h"
15#include "src/objects/shared-function-info-inl.h"
16#include "src/objects/string-inl.h"
17
18namespace v8 {
19namespace internal {
20
21bool FunctionTemplateInfo::HasInstanceType() {
22  return instance_type() != kNoJSApiObjectType;
23}
24
25Handle<SharedFunctionInfo> FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(
26    Isolate* isolate, Handle<FunctionTemplateInfo> info,
27    MaybeHandle<Name> maybe_name) {
28  Object current_info = info->shared_function_info();
29  if (current_info.IsSharedFunctionInfo()) {
30    return handle(SharedFunctionInfo::cast(current_info), isolate);
31  }
32  Handle<Name> name;
33  Handle<String> name_string;
34  if (maybe_name.ToHandle(&name) && name->IsString()) {
35    name_string = Handle<String>::cast(name);
36  } else if (info->class_name().IsString()) {
37    name_string = handle(String::cast(info->class_name()), isolate);
38  } else {
39    name_string = isolate->factory()->empty_string();
40  }
41  FunctionKind function_kind;
42  if (info->remove_prototype()) {
43    function_kind = FunctionKind::kConciseMethod;
44  } else {
45    function_kind = FunctionKind::kNormalFunction;
46  }
47  Handle<SharedFunctionInfo> result =
48      isolate->factory()->NewSharedFunctionInfoForApiFunction(name_string, info,
49                                                              function_kind);
50
51  result->set_length(info->length());
52  result->DontAdaptArguments();
53  DCHECK(result->IsApiFunction());
54
55  info->set_shared_function_info(*result);
56  return result;
57}
58
59bool FunctionTemplateInfo::IsTemplateFor(Map map) const {
60  RCS_SCOPE(
61      LocalHeap::Current() == nullptr
62          ? GetIsolate()->counters()->runtime_call_stats()
63          : LocalIsolate::FromHeap(LocalHeap::Current())->runtime_call_stats(),
64      RuntimeCallCounterId::kIsTemplateFor);
65
66  // There is a constraint on the object; check.
67  if (!map.IsJSObjectMap()) return false;
68
69  if (FLAG_embedder_instance_types) {
70    DCHECK_IMPLIES(allowed_receiver_instance_type_range_start() == 0,
71                   allowed_receiver_instance_type_range_end() == 0);
72    if (base::IsInRange(map.instance_type(),
73                        allowed_receiver_instance_type_range_start(),
74                        allowed_receiver_instance_type_range_end())) {
75      return true;
76    }
77  }
78
79  // Fetch the constructor function of the object.
80  Object cons_obj = map.GetConstructor();
81  Object type;
82  if (cons_obj.IsJSFunction()) {
83    JSFunction fun = JSFunction::cast(cons_obj);
84    type = fun.shared().function_data(kAcquireLoad);
85  } else if (cons_obj.IsFunctionTemplateInfo()) {
86    type = FunctionTemplateInfo::cast(cons_obj);
87  } else {
88    return false;
89  }
90  // Iterate through the chain of inheriting function templates to
91  // see if the required one occurs.
92  while (type.IsFunctionTemplateInfo()) {
93    if (type == *this) return true;
94    type = FunctionTemplateInfo::cast(type).GetParentTemplate();
95  }
96  // Didn't find the required type in the inheritance chain.
97  return false;
98}
99
100bool FunctionTemplateInfo::IsLeafTemplateForApiObject(Object object) const {
101  i::DisallowGarbageCollection no_gc;
102
103  if (!object.IsJSApiObject()) {
104    return false;
105  }
106
107  bool result = false;
108  Map map = HeapObject::cast(object).map();
109  Object constructor_obj = map.GetConstructor();
110  if (constructor_obj.IsJSFunction()) {
111    JSFunction fun = JSFunction::cast(constructor_obj);
112    result = (*this == fun.shared().function_data(kAcquireLoad));
113  } else if (constructor_obj.IsFunctionTemplateInfo()) {
114    result = (*this == constructor_obj);
115  }
116  DCHECK_IMPLIES(result, IsTemplateFor(map));
117  return result;
118}
119
120// static
121FunctionTemplateRareData FunctionTemplateInfo::AllocateFunctionTemplateRareData(
122    Isolate* isolate, Handle<FunctionTemplateInfo> function_template_info) {
123  DCHECK(function_template_info->rare_data(kAcquireLoad).IsUndefined(isolate));
124  Handle<FunctionTemplateRareData> rare_data =
125      isolate->factory()->NewFunctionTemplateRareData();
126  function_template_info->set_rare_data(*rare_data, kReleaseStore);
127  return *rare_data;
128}
129
130base::Optional<Name> FunctionTemplateInfo::TryGetCachedPropertyName(
131    Isolate* isolate, Object getter) {
132  DisallowGarbageCollection no_gc;
133  if (!getter.IsFunctionTemplateInfo()) return {};
134  // Check if the accessor uses a cached property.
135  Object maybe_name = FunctionTemplateInfo::cast(getter).cached_property_name();
136  if (maybe_name.IsTheHole(isolate)) return {};
137  return Name::cast(maybe_name);
138}
139
140int FunctionTemplateInfo::GetCFunctionsCount() const {
141  i::DisallowHeapAllocation no_gc;
142  return FixedArray::cast(GetCFunctionOverloads()).length() /
143         kFunctionOverloadEntrySize;
144}
145
146Address FunctionTemplateInfo::GetCFunction(int index) const {
147  i::DisallowHeapAllocation no_gc;
148  return v8::ToCData<Address>(FixedArray::cast(GetCFunctionOverloads())
149                                  .get(index * kFunctionOverloadEntrySize));
150}
151
152const CFunctionInfo* FunctionTemplateInfo::GetCSignature(int index) const {
153  i::DisallowHeapAllocation no_gc;
154  return v8::ToCData<CFunctionInfo*>(
155      FixedArray::cast(GetCFunctionOverloads())
156          .get(index * kFunctionOverloadEntrySize + 1));
157}
158
159}  // namespace internal
160}  // namespace v8
161