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/template-objects.h"
6
7#include "src/base/functional.h"
8#include "src/execution/isolate.h"
9#include "src/heap/factory.h"
10#include "src/objects/objects-inl.h"
11#include "src/objects/property-descriptor.h"
12#include "src/objects/template-objects-inl.h"
13
14namespace v8 {
15namespace internal {
16
17// static
18Handle<JSArray> TemplateObjectDescription::GetTemplateObject(
19    Isolate* isolate, Handle<NativeContext> native_context,
20    Handle<TemplateObjectDescription> description,
21    Handle<SharedFunctionInfo> shared_info, int slot_id) {
22  uint32_t hash = shared_info->Hash();
23
24  // Check the template weakmap to see if the template object already exists.
25  Handle<EphemeronHashTable> template_weakmap;
26
27  if (native_context->template_weakmap().IsUndefined(isolate)) {
28    template_weakmap = EphemeronHashTable::New(isolate, 1);
29  } else {
30    DisallowGarbageCollection no_gc;
31    ReadOnlyRoots roots(isolate);
32    template_weakmap = handle(
33        EphemeronHashTable::cast(native_context->template_weakmap()), isolate);
34    Object maybe_cached_template = template_weakmap->Lookup(shared_info, hash);
35    while (!maybe_cached_template.IsTheHole(roots)) {
36      CachedTemplateObject cached_template =
37          CachedTemplateObject::cast(maybe_cached_template);
38      if (cached_template.slot_id() == slot_id) {
39        return handle(cached_template.template_object(), isolate);
40      }
41      maybe_cached_template = cached_template.next();
42    }
43  }
44
45  // Create the raw object from the {raw_strings}.
46  Handle<FixedArray> raw_strings(description->raw_strings(), isolate);
47  Handle<JSArray> raw_object = isolate->factory()->NewJSArrayWithElements(
48      raw_strings, PACKED_ELEMENTS, raw_strings->length(),
49      AllocationType::kOld);
50
51  // Create the template object from the {cooked_strings}.
52  Handle<FixedArray> cooked_strings(description->cooked_strings(), isolate);
53  Handle<JSArray> template_object = isolate->factory()->NewJSArrayWithElements(
54      cooked_strings, PACKED_ELEMENTS, cooked_strings->length(),
55      AllocationType::kOld);
56
57  // Freeze the {raw_object}.
58  JSObject::SetIntegrityLevel(raw_object, FROZEN, kThrowOnError).ToChecked();
59
60  // Install a "raw" data property for {raw_object} on {template_object}.
61  PropertyDescriptor raw_desc;
62  raw_desc.set_value(raw_object);
63  raw_desc.set_configurable(false);
64  raw_desc.set_enumerable(false);
65  raw_desc.set_writable(false);
66  JSArray::DefineOwnProperty(isolate, template_object,
67                             isolate->factory()->raw_string(), &raw_desc,
68                             Just(kThrowOnError))
69      .ToChecked();
70
71  // Freeze the {template_object} as well.
72  JSObject::SetIntegrityLevel(template_object, FROZEN, kThrowOnError)
73      .ToChecked();
74
75  // Insert the template object into the template weakmap.
76  Handle<HeapObject> previous_cached_templates = handle(
77      HeapObject::cast(template_weakmap->Lookup(shared_info, hash)), isolate);
78  Handle<CachedTemplateObject> cached_template = CachedTemplateObject::New(
79      isolate, slot_id, template_object, previous_cached_templates);
80  template_weakmap = EphemeronHashTable::Put(
81      isolate, template_weakmap, shared_info, cached_template, hash);
82  native_context->set_template_weakmap(*template_weakmap);
83
84  return template_object;
85}
86
87Handle<CachedTemplateObject> CachedTemplateObject::New(
88    Isolate* isolate, int slot_id, Handle<JSArray> template_object,
89    Handle<HeapObject> next) {
90  DCHECK(next->IsCachedTemplateObject() || next->IsTheHole());
91  Handle<CachedTemplateObject> result_handle =
92      Handle<CachedTemplateObject>::cast(isolate->factory()->NewStruct(
93          CACHED_TEMPLATE_OBJECT_TYPE, AllocationType::kOld));
94  {
95    DisallowGarbageCollection no_gc;
96    auto result = *result_handle;
97    result.set_slot_id(slot_id);
98    result.set_template_object(*template_object);
99    result.set_next(*next);
100  }
101  return result_handle;
102}
103
104}  // namespace internal
105}  // namespace v8
106