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