V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
literal-objects.cc
1 // Copyright 2017 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/literal-objects.h"
6 
7 #include "src/accessors.h"
8 #include "src/ast/ast.h"
9 #include "src/heap/factory.h"
10 #include "src/isolate.h"
11 #include "src/objects-inl.h"
12 #include "src/objects/hash-table-inl.h"
13 #include "src/objects/literal-objects-inl.h"
14 #include "src/objects/smi.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 Object* ObjectBoilerplateDescription::name(int index) const {
20  // get() already checks for out of bounds access, but we do not want to allow
21  // access to the last element, if it is the number of properties.
22  DCHECK_NE(size(), index);
23  return get(2 * index + kDescriptionStartIndex);
24 }
25 
26 Object* ObjectBoilerplateDescription::value(int index) const {
27  return get(2 * index + 1 + kDescriptionStartIndex);
28 }
29 
30 void ObjectBoilerplateDescription::set_key_value(int index, Object* key,
31  Object* value) {
32  DCHECK_LT(index, size());
33  DCHECK_GE(index, 0);
34  set(2 * index + kDescriptionStartIndex, key);
35  set(2 * index + 1 + kDescriptionStartIndex, value);
36 }
37 
38 int ObjectBoilerplateDescription::size() const {
39  DCHECK_EQ(0, (length() - kDescriptionStartIndex -
40  (this->has_number_of_properties() ? 1 : 0)) %
41  2);
42  // Rounding is intended.
43  return (length() - kDescriptionStartIndex) / 2;
44 }
45 
46 int ObjectBoilerplateDescription::backing_store_size() const {
47  if (has_number_of_properties()) {
48  // If present, the last entry contains the number of properties.
49  return Smi::ToInt(this->get(length() - 1));
50  }
51  // If the number is not given explicitly, we assume there are no
52  // properties with computed names.
53  return size();
54 }
55 
56 void ObjectBoilerplateDescription::set_backing_store_size(
57  Isolate* isolate, int backing_store_size) {
58  DCHECK(has_number_of_properties());
59  DCHECK_NE(size(), backing_store_size);
60  Handle<Object> backing_store_size_obj =
61  isolate->factory()->NewNumberFromInt(backing_store_size);
62  set(length() - 1, *backing_store_size_obj);
63 }
64 
65 bool ObjectBoilerplateDescription::has_number_of_properties() const {
66  return (length() - kDescriptionStartIndex) % 2 != 0;
67 }
68 
69 namespace {
70 
71 inline int EncodeComputedEntry(ClassBoilerplate::ValueKind value_kind,
72  unsigned key_index) {
73  typedef ClassBoilerplate::ComputedEntryFlags Flags;
74  int flags = Flags::ValueKindBits::encode(value_kind) |
75  Flags::KeyIndexBits::encode(key_index);
76  return flags;
77 }
78 
79 void AddToDescriptorArrayTemplate(
80  Isolate* isolate, Handle<DescriptorArray> descriptor_array_template,
81  Handle<Name> name, ClassBoilerplate::ValueKind value_kind,
82  Handle<Object> value) {
83  int entry = descriptor_array_template->Search(
84  *name, descriptor_array_template->number_of_descriptors());
85  // TODO(ishell): deduplicate properties at AST level, this will allow us to
86  // avoid creation of closures that will be overwritten anyway.
87  if (entry == DescriptorArray::kNotFound) {
88  // Entry not found, add new one.
89  Descriptor d;
90  if (value_kind == ClassBoilerplate::kData) {
91  d = Descriptor::DataConstant(name, value, DONT_ENUM);
92  } else {
93  DCHECK(value_kind == ClassBoilerplate::kGetter ||
94  value_kind == ClassBoilerplate::kSetter);
95  Handle<AccessorPair> pair = isolate->factory()->NewAccessorPair();
96  pair->set(value_kind == ClassBoilerplate::kGetter ? ACCESSOR_GETTER
97  : ACCESSOR_SETTER,
98  *value);
99  d = Descriptor::AccessorConstant(name, pair, DONT_ENUM);
100  }
101  descriptor_array_template->Append(&d);
102 
103  } else {
104  // Entry found, update it.
105  int sorted_index = descriptor_array_template->GetDetails(entry).pointer();
106  if (value_kind == ClassBoilerplate::kData) {
107  Descriptor d = Descriptor::DataConstant(name, value, DONT_ENUM);
108  d.SetSortedKeyIndex(sorted_index);
109  descriptor_array_template->Set(entry, &d);
110  } else {
111  DCHECK(value_kind == ClassBoilerplate::kGetter ||
112  value_kind == ClassBoilerplate::kSetter);
113  Object* raw_accessor = descriptor_array_template->GetStrongValue(entry);
114  AccessorPair* pair;
115  if (raw_accessor->IsAccessorPair()) {
116  pair = AccessorPair::cast(raw_accessor);
117  } else {
118  Handle<AccessorPair> new_pair = isolate->factory()->NewAccessorPair();
119  Descriptor d = Descriptor::AccessorConstant(name, new_pair, DONT_ENUM);
120  d.SetSortedKeyIndex(sorted_index);
121  descriptor_array_template->Set(entry, &d);
122  pair = *new_pair;
123  }
124  pair->set(value_kind == ClassBoilerplate::kGetter ? ACCESSOR_GETTER
125  : ACCESSOR_SETTER,
126  *value);
127  }
128  }
129 }
130 
131 Handle<NameDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
132  Isolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
133  Handle<Object> value, PropertyDetails details, int* entry_out = nullptr) {
134  return NameDictionary::AddNoUpdateNextEnumerationIndex(
135  isolate, dictionary, name, value, details, entry_out);
136 }
137 
138 Handle<NumberDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
139  Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t element,
140  Handle<Object> value, PropertyDetails details, int* entry_out = nullptr) {
141  // NumberDictionary does not maintain the enumeration order, so it's
142  // a normal Add().
143  return NumberDictionary::Add(isolate, dictionary, element, value, details,
144  entry_out);
145 }
146 
147 void DictionaryUpdateMaxNumberKey(Handle<NameDictionary> dictionary,
148  Handle<Name> name) {
149  // No-op for name dictionaries.
150 }
151 
152 void DictionaryUpdateMaxNumberKey(Handle<NumberDictionary> dictionary,
153  uint32_t element) {
154  dictionary->UpdateMaxNumberKey(element, Handle<JSObject>());
155  dictionary->set_requires_slow_elements();
156 }
157 
158 constexpr int ComputeEnumerationIndex(int value_index) {
159  // We "shift" value indices to ensure that the enumeration index for the value
160  // will not overlap with minimum properties set for both class and prototype
161  // objects.
162  return value_index + Max(ClassBoilerplate::kMinimumClassPropertiesCount,
163  ClassBoilerplate::kMinimumPrototypePropertiesCount);
164 }
165 
166 inline int GetExistingValueIndex(Object* value) {
167  return value->IsSmi() ? Smi::ToInt(value) : -1;
168 }
169 
170 template <typename Dictionary, typename Key>
171 void AddToDictionaryTemplate(Isolate* isolate, Handle<Dictionary> dictionary,
172  Key key, int key_index,
173  ClassBoilerplate::ValueKind value_kind,
174  Object* value) {
175  int entry = dictionary->FindEntry(isolate, key);
176 
177  if (entry == kNotFound) {
178  // Entry not found, add new one.
179  const bool is_elements_dictionary =
180  std::is_same<Dictionary, NumberDictionary>::value;
181  STATIC_ASSERT(is_elements_dictionary !=
182  (std::is_same<Dictionary, NameDictionary>::value));
183  int enum_order =
184  is_elements_dictionary ? 0 : ComputeEnumerationIndex(key_index);
185  Handle<Object> value_handle;
186  PropertyDetails details(
187  value_kind != ClassBoilerplate::kData ? kAccessor : kData, DONT_ENUM,
188  PropertyCellType::kNoCell, enum_order);
189 
190  if (value_kind == ClassBoilerplate::kData) {
191  value_handle = handle(value, isolate);
192  } else {
193  AccessorComponent component = value_kind == ClassBoilerplate::kGetter
194  ? ACCESSOR_GETTER
195  : ACCESSOR_SETTER;
196  Handle<AccessorPair> pair(isolate->factory()->NewAccessorPair());
197  pair->set(component, value);
198  value_handle = pair;
199  }
200 
201  // Add value to the dictionary without updating next enumeration index.
202  Handle<Dictionary> dict = DictionaryAddNoUpdateNextEnumerationIndex(
203  isolate, dictionary, key, value_handle, details, &entry);
204  // It is crucial to avoid dictionary reallocations because it may remove
205  // potential gaps in enumeration indices values that are necessary for
206  // inserting computed properties into right places in the enumeration order.
207  CHECK_EQ(*dict, *dictionary);
208 
209  DictionaryUpdateMaxNumberKey(dictionary, key);
210 
211  } else {
212  // Entry found, update it.
213  int enum_order = dictionary->DetailsAt(entry).dictionary_index();
214  Object* existing_value = dictionary->ValueAt(entry);
215  if (value_kind == ClassBoilerplate::kData) {
216  // Computed value is a normal method.
217  if (existing_value->IsAccessorPair()) {
218  AccessorPair* current_pair = AccessorPair::cast(existing_value);
219 
220  int existing_getter_index =
221  GetExistingValueIndex(current_pair->getter());
222  int existing_setter_index =
223  GetExistingValueIndex(current_pair->setter());
224  // At least one of the accessors must already be defined.
225  DCHECK(existing_getter_index >= 0 || existing_setter_index >= 0);
226  if (existing_getter_index < key_index &&
227  existing_setter_index < key_index) {
228  // Either both getter and setter were defined before the computed
229  // method or just one of them was defined before while the other one
230  // was not defined yet, so overwrite property to kData.
231  PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell,
232  enum_order);
233  dictionary->DetailsAtPut(isolate, entry, details);
234  dictionary->ValueAtPut(entry, value);
235 
236  } else {
237  // The data property was defined "between" accessors so the one that
238  // was overwritten has to be cleared.
239  if (existing_getter_index < key_index) {
240  DCHECK_LT(key_index, existing_setter_index);
241  // Getter was defined and it was done before the computed method
242  // and then it was overwritten by the current computed method which
243  // in turn was later overwritten by the setter method. So we clear
244  // the getter.
245  current_pair->set_getter(*isolate->factory()->null_value());
246 
247  } else if (existing_setter_index < key_index) {
248  DCHECK_LT(key_index, existing_getter_index);
249  // Setter was defined and it was done before the computed method
250  // and then it was overwritten by the current computed method which
251  // in turn was later overwritten by the getter method. So we clear
252  // the setter.
253  current_pair->set_setter(*isolate->factory()->null_value());
254  }
255  }
256  } else {
257  // Overwrite existing value if it was defined before the computed one.
258  int existing_value_index = Smi::ToInt(existing_value);
259  if (existing_value_index < key_index) {
260  PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell,
261  enum_order);
262  dictionary->DetailsAtPut(isolate, entry, details);
263  dictionary->ValueAtPut(entry, value);
264  }
265  }
266  } else {
267  AccessorComponent component = value_kind == ClassBoilerplate::kGetter
268  ? ACCESSOR_GETTER
269  : ACCESSOR_SETTER;
270  if (existing_value->IsAccessorPair()) {
271  AccessorPair* current_pair = AccessorPair::cast(existing_value);
272 
273  int existing_component_index =
274  GetExistingValueIndex(current_pair->get(component));
275  if (existing_component_index < key_index) {
276  current_pair->set(component, value);
277  }
278 
279  } else {
280  Handle<AccessorPair> pair(isolate->factory()->NewAccessorPair());
281  pair->set(component, value);
282  PropertyDetails details(kAccessor, DONT_ENUM, PropertyCellType::kNoCell,
283  enum_order);
284  dictionary->DetailsAtPut(isolate, entry, details);
285  dictionary->ValueAtPut(entry, *pair);
286  }
287  }
288  }
289 }
290 
291 } // namespace
292 
293 // Helper class that eases building of a properties, elements and computed
294 // properties templates.
296  public:
297  void IncComputedCount() { ++computed_count_; }
298  void IncPropertiesCount() { ++property_count_; }
299  void IncElementsCount() { ++element_count_; }
300 
301  bool HasDictionaryProperties() const {
302  return computed_count_ > 0 || property_count_ > kMaxNumberOfDescriptors;
303  }
304 
305  Handle<Object> properties_template() const {
306  return HasDictionaryProperties()
307  ? Handle<Object>::cast(properties_dictionary_template_)
308  : Handle<Object>::cast(descriptor_array_template_);
309  }
310 
311  Handle<NumberDictionary> elements_template() const {
312  return elements_dictionary_template_;
313  }
314 
315  Handle<FixedArray> computed_properties() const {
316  return computed_properties_;
317  }
318 
319  void CreateTemplates(Isolate* isolate, int slack) {
320  Factory* factory = isolate->factory();
321  descriptor_array_template_ = factory->empty_descriptor_array();
322  properties_dictionary_template_ = factory->empty_property_dictionary();
323  if (property_count_ || HasDictionaryProperties() || slack) {
324  if (HasDictionaryProperties()) {
325  properties_dictionary_template_ = NameDictionary::New(
326  isolate, property_count_ + computed_count_ + slack);
327  } else {
328  descriptor_array_template_ =
329  DescriptorArray::Allocate(isolate, 0, property_count_ + slack);
330  }
331  }
332  elements_dictionary_template_ =
333  element_count_ || computed_count_
334  ? NumberDictionary::New(isolate, element_count_ + computed_count_)
335  : factory->empty_slow_element_dictionary();
336 
337  computed_properties_ =
338  computed_count_
339  ? factory->NewFixedArray(computed_count_ *
340  ClassBoilerplate::kFullComputedEntrySize)
341  : factory->empty_fixed_array();
342 
343  temp_handle_ = handle(Smi::kZero, isolate);
344  }
345 
346  void AddConstant(Isolate* isolate, Handle<Name> name, Handle<Object> value,
347  PropertyAttributes attribs) {
348  bool is_accessor = value->IsAccessorInfo();
349  DCHECK(!value->IsAccessorPair());
350  if (HasDictionaryProperties()) {
351  PropertyKind kind = is_accessor ? i::kAccessor : i::kData;
352  PropertyDetails details(kind, attribs, PropertyCellType::kNoCell,
353  next_enumeration_index_++);
354  properties_dictionary_template_ =
355  DictionaryAddNoUpdateNextEnumerationIndex(
356  isolate, properties_dictionary_template_, name, value, details);
357  } else {
358  Descriptor d = is_accessor
359  ? Descriptor::AccessorConstant(name, value, attribs)
360  : Descriptor::DataConstant(name, value, attribs);
361  descriptor_array_template_->Append(&d);
362  }
363  }
364 
365  void AddNamedProperty(Isolate* isolate, Handle<Name> name,
366  ClassBoilerplate::ValueKind value_kind,
367  int value_index) {
368  Smi value = Smi::FromInt(value_index);
369  if (HasDictionaryProperties()) {
370  UpdateNextEnumerationIndex(value_index);
371  AddToDictionaryTemplate(isolate, properties_dictionary_template_, name,
372  value_index, value_kind, value);
373  } else {
374  *temp_handle_.location() = value->ptr();
375  AddToDescriptorArrayTemplate(isolate, descriptor_array_template_, name,
376  value_kind, temp_handle_);
377  }
378  }
379 
380  void AddIndexedProperty(Isolate* isolate, uint32_t element,
381  ClassBoilerplate::ValueKind value_kind,
382  int value_index) {
383  Smi value = Smi::FromInt(value_index);
384  AddToDictionaryTemplate(isolate, elements_dictionary_template_, element,
385  value_index, value_kind, value);
386  }
387 
388  void AddComputed(ClassBoilerplate::ValueKind value_kind, int key_index) {
389  int value_index = key_index + 1;
390  UpdateNextEnumerationIndex(value_index);
391 
392  int flags = EncodeComputedEntry(value_kind, key_index);
393  computed_properties_->set(current_computed_index_++, Smi::FromInt(flags));
394  }
395 
396  void UpdateNextEnumerationIndex(int value_index) {
397  int next_index = ComputeEnumerationIndex(value_index);
398  DCHECK_LT(next_enumeration_index_, next_index);
399  next_enumeration_index_ = next_index;
400  }
401 
402  void Finalize(Isolate* isolate) {
403  if (HasDictionaryProperties()) {
404  properties_dictionary_template_->SetNextEnumerationIndex(
405  next_enumeration_index_);
406  computed_properties_ = FixedArray::ShrinkOrEmpty(
407  isolate, computed_properties_, current_computed_index_);
408  } else {
409  DCHECK(descriptor_array_template_->IsSortedNoDuplicates());
410  }
411  }
412 
413  private:
414  int property_count_ = 0;
415  int next_enumeration_index_ = PropertyDetails::kInitialIndex;
416  int element_count_ = 0;
417  int computed_count_ = 0;
418  int current_computed_index_ = 0;
419 
420  Handle<DescriptorArray> descriptor_array_template_;
421  Handle<NameDictionary> properties_dictionary_template_;
422  Handle<NumberDictionary> elements_dictionary_template_;
423  Handle<FixedArray> computed_properties_;
424  // This temporary handle is used for storing to descriptor array.
425  Handle<Object> temp_handle_;
426 };
427 
428 void ClassBoilerplate::AddToPropertiesTemplate(
429  Isolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
430  int key_index, ClassBoilerplate::ValueKind value_kind, Object* value) {
431  AddToDictionaryTemplate(isolate, dictionary, name, key_index, value_kind,
432  value);
433 }
434 
435 void ClassBoilerplate::AddToElementsTemplate(
436  Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
437  int key_index, ClassBoilerplate::ValueKind value_kind, Object* value) {
438  AddToDictionaryTemplate(isolate, dictionary, key, key_index, value_kind,
439  value);
440 }
441 
442 Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
443  Isolate* isolate, ClassLiteral* expr) {
444  // Create a non-caching handle scope to ensure that the temporary handle used
445  // by ObjectDescriptor for passing Smis around does not corrupt handle cache
446  // in CanonicalHandleScope.
447  HandleScope scope(isolate);
448  Factory* factory = isolate->factory();
449  ObjectDescriptor static_desc;
450  ObjectDescriptor instance_desc;
451 
452  for (int i = 0; i < expr->properties()->length(); i++) {
453  ClassLiteral::Property* property = expr->properties()->at(i);
454  ObjectDescriptor& desc =
455  property->is_static() ? static_desc : instance_desc;
456  if (property->is_computed_name()) {
457  desc.IncComputedCount();
458  } else {
459  if (property->key()->AsLiteral()->IsPropertyName()) {
460  desc.IncPropertiesCount();
461  } else {
462  desc.IncElementsCount();
463  }
464  }
465  }
466 
467  //
468  // Initialize class object template.
469  //
470  static_desc.CreateTemplates(isolate, kMinimumClassPropertiesCount);
471  STATIC_ASSERT(JSFunction::kLengthDescriptorIndex == 0);
472  {
473  // Add length_accessor.
474  PropertyAttributes attribs =
475  static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
476  static_desc.AddConstant(isolate, factory->length_string(),
477  factory->function_length_accessor(), attribs);
478  }
479  {
480  // Add prototype_accessor.
481  PropertyAttributes attribs =
482  static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
483  static_desc.AddConstant(isolate, factory->prototype_string(),
484  factory->function_prototype_accessor(), attribs);
485  }
486  if (FunctionLiteral::NeedsHomeObject(expr->constructor())) {
487  PropertyAttributes attribs =
488  static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
489  Handle<Object> value(
490  Smi::FromInt(ClassBoilerplate::kPrototypeArgumentIndex), isolate);
491  static_desc.AddConstant(isolate, factory->home_object_symbol(), value,
492  attribs);
493  }
494  {
495  Handle<Smi> start_position(Smi::FromInt(expr->start_position()), isolate);
496  Handle<Smi> end_position(Smi::FromInt(expr->end_position()), isolate);
497  Handle<Tuple2> class_positions =
498  factory->NewTuple2(start_position, end_position, NOT_TENURED);
499  static_desc.AddConstant(isolate, factory->class_positions_symbol(),
500  class_positions, DONT_ENUM);
501  }
502 
503  //
504  // Initialize prototype object template.
505  //
506  instance_desc.CreateTemplates(isolate, kMinimumPrototypePropertiesCount);
507  {
508  Handle<Object> value(
509  Smi::FromInt(ClassBoilerplate::kConstructorArgumentIndex), isolate);
510  instance_desc.AddConstant(isolate, factory->constructor_string(), value,
511  DONT_ENUM);
512  }
513 
514  //
515  // Fill in class boilerplate.
516  //
517  int dynamic_argument_index = ClassBoilerplate::kFirstDynamicArgumentIndex;
518 
519  for (int i = 0; i < expr->properties()->length(); i++) {
520  ClassLiteral::Property* property = expr->properties()->at(i);
521 
522  ClassBoilerplate::ValueKind value_kind;
523  switch (property->kind()) {
524  case ClassLiteral::Property::METHOD:
525  value_kind = ClassBoilerplate::kData;
526  break;
527  case ClassLiteral::Property::GETTER:
528  value_kind = ClassBoilerplate::kGetter;
529  break;
530  case ClassLiteral::Property::SETTER:
531  value_kind = ClassBoilerplate::kSetter;
532  break;
533  case ClassLiteral::Property::FIELD:
534  DCHECK_IMPLIES(property->is_computed_name(), !property->is_private());
535  if (property->is_computed_name()) {
536  ++dynamic_argument_index;
537  }
538  continue;
539  }
540 
541  ObjectDescriptor& desc =
542  property->is_static() ? static_desc : instance_desc;
543  if (property->is_computed_name()) {
544  int computed_name_index = dynamic_argument_index;
545  dynamic_argument_index += 2; // Computed name and value indices.
546  desc.AddComputed(value_kind, computed_name_index);
547  continue;
548  }
549  int value_index = dynamic_argument_index++;
550 
551  Literal* key_literal = property->key()->AsLiteral();
552  uint32_t index;
553  if (key_literal->AsArrayIndex(&index)) {
554  desc.AddIndexedProperty(isolate, index, value_kind, value_index);
555 
556  } else {
557  Handle<String> name = key_literal->AsRawPropertyName()->string();
558  DCHECK(name->IsInternalizedString());
559  desc.AddNamedProperty(isolate, name, value_kind, value_index);
560  }
561  }
562 
563  // Add name accessor to the class object if necessary.
564  bool install_class_name_accessor = false;
565  if (!expr->has_name_static_property() &&
566  expr->constructor()->has_shared_name()) {
567  if (static_desc.HasDictionaryProperties()) {
568  // Install class name accessor if necessary during class literal
569  // instantiation.
570  install_class_name_accessor = true;
571  } else {
572  // Set class name accessor if the "name" method was not added yet.
573  PropertyAttributes attribs =
574  static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
575  static_desc.AddConstant(isolate, factory->name_string(),
576  factory->function_name_accessor(), attribs);
577  }
578  }
579 
580  static_desc.Finalize(isolate);
581  instance_desc.Finalize(isolate);
582 
583  Handle<ClassBoilerplate> class_boilerplate =
584  Handle<ClassBoilerplate>::cast(factory->NewFixedArray(kBoileplateLength));
585 
586  class_boilerplate->set_flags(0);
587  class_boilerplate->set_install_class_name_accessor(
588  install_class_name_accessor);
589  class_boilerplate->set_arguments_count(dynamic_argument_index);
590 
591  class_boilerplate->set_static_properties_template(
592  *static_desc.properties_template());
593  class_boilerplate->set_static_elements_template(
594  *static_desc.elements_template());
595  class_boilerplate->set_static_computed_properties(
596  *static_desc.computed_properties());
597 
598  class_boilerplate->set_instance_properties_template(
599  *instance_desc.properties_template());
600  class_boilerplate->set_instance_elements_template(
601  *instance_desc.elements_template());
602  class_boilerplate->set_instance_computed_properties(
603  *instance_desc.computed_properties());
604 
605  return scope.CloseAndEscape(class_boilerplate);
606 }
607 
608 } // namespace internal
609 } // namespace v8
Definition: v8.h:85
Definition: libplatform.h:13