summaryrefslogtreecommitdiffstats
path: root/chromium/v8/src/objects/template-objects.cc
blob: 06e18695dde980afab3942e9e0110c4975f6a350 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/objects/template-objects.h"

#include "src/base/functional.h"
#include "src/execution/isolate.h"
#include "src/heap/factory.h"
#include "src/objects/js-array.h"
#include "src/objects/objects-inl.h"
#include "src/objects/property-descriptor.h"
#include "src/objects/template-objects-inl.h"

namespace v8 {
namespace internal {

namespace {
bool CachedTemplateMatches(Isolate* isolate,
                           Tagged<NativeContext> native_context,
                           Tagged<JSArray> entry, int function_literal_id,
                           int slot_id, DisallowGarbageCollection& no_gc) {
  if (native_context->is_js_array_template_literal_object_map(
          entry->map(isolate))) {
    Tagged<TemplateLiteralObject> template_object =
        TemplateLiteralObject::cast(entry);
    return template_object->function_literal_id() == function_literal_id &&
           template_object->slot_id() == slot_id;
  }

  Handle<JSArray> entry_handle(entry, isolate);
  Tagged<Smi> cached_function_literal_id =
      Smi::cast(*JSReceiver::GetDataProperty(
          isolate, entry_handle,
          isolate->factory()->template_literal_function_literal_id_symbol()));
  if (cached_function_literal_id.value() != function_literal_id) return false;

  Tagged<Smi> cached_slot_id = Smi::cast(*JSReceiver::GetDataProperty(
      isolate, entry_handle,
      isolate->factory()->template_literal_slot_id_symbol()));
  if (cached_slot_id.value() != slot_id) return false;

  return true;
}
}  // namespace

// static
Handle<JSArray> TemplateObjectDescription::GetTemplateObject(
    Isolate* isolate, Handle<NativeContext> native_context,
    Handle<TemplateObjectDescription> description,
    Handle<SharedFunctionInfo> shared_info, int slot_id) {
  int function_literal_id = shared_info->function_literal_id();

  // Check the template weakmap to see if the template object already exists.
  Handle<Script> script(Script::cast(shared_info->script(isolate)), isolate);
  int32_t hash =
      EphemeronHashTable::ShapeT::Hash(ReadOnlyRoots(isolate), script);
  MaybeHandle<ArrayList> maybe_cached_templates;

  if (!IsUndefined(native_context->template_weakmap(), isolate)) {
    DisallowGarbageCollection no_gc;
    // The no_gc keeps this safe, and gcmole is confused because
    // CachedTemplateMatches calls JSReceiver::GetDataProperty.
    DisableGCMole no_gcmole;
    ReadOnlyRoots roots(isolate);
    Tagged<EphemeronHashTable> template_weakmap =
        EphemeronHashTable::cast(native_context->template_weakmap());
    Tagged<Object> cached_templates_lookup =
        template_weakmap->Lookup(isolate, script, hash);
    if (!IsTheHole(cached_templates_lookup, roots)) {
      Tagged<ArrayList> cached_templates =
          ArrayList::cast(cached_templates_lookup);
      maybe_cached_templates = handle(cached_templates, isolate);

      // Linear search over the cached template array list for a template
      // object matching the given function_literal_id + slot_id.
      // TODO(leszeks): Consider keeping this list sorted for faster lookup.
      for (int i = 0; i < cached_templates->Length(); i++) {
        Tagged<JSArray> template_object =
            JSArray::cast(cached_templates->Get(i));
        if (CachedTemplateMatches(isolate, *native_context, template_object,
                                  function_literal_id, slot_id, no_gc)) {
          return handle(template_object, isolate);
        }
      }
    }
  }

  // Create the raw object from the {raw_strings}.
  Handle<FixedArray> raw_strings(description->raw_strings(), isolate);
  Handle<FixedArray> cooked_strings(description->cooked_strings(), isolate);
  Handle<JSArray> template_object =
      isolate->factory()->NewJSArrayForTemplateLiteralArray(
          cooked_strings, raw_strings, function_literal_id, slot_id);

  // Insert the template object into the cached template array list.
  Handle<ArrayList> cached_templates;
  if (!maybe_cached_templates.ToHandle(&cached_templates)) {
    cached_templates = isolate->factory()->NewArrayList(1);
  }
  cached_templates = ArrayList::Add(isolate, cached_templates, template_object);

  // Compare the cached_templates to the original maybe_cached_templates loaded
  // from the weakmap -- if it doesn't match, we need to update the weakmap.
  Handle<ArrayList> old_cached_templates;
  if (!maybe_cached_templates.ToHandle(&old_cached_templates) ||
      *old_cached_templates != *cached_templates) {
    Tagged<HeapObject> maybe_template_weakmap =
        native_context->template_weakmap();
    Handle<EphemeronHashTable> template_weakmap;
    if (IsUndefined(maybe_template_weakmap)) {
      template_weakmap = EphemeronHashTable::New(isolate, 1);
    } else {
      template_weakmap =
          handle(EphemeronHashTable::cast(maybe_template_weakmap), isolate);
    }
    template_weakmap = EphemeronHashTable::Put(isolate, template_weakmap,
                                               script, cached_templates, hash);
    native_context->set_template_weakmap(*template_weakmap);
  }

  // Check that the list is in the appropriate location on the weakmap, and
  // that the appropriate entry is in the right location in this list.
  DCHECK_EQ(EphemeronHashTable::cast(native_context->template_weakmap())
                ->Lookup(isolate, script, hash),
            *cached_templates);
  DCHECK_EQ(cached_templates->Get(cached_templates->Length() - 1),
            *template_object);

  return template_object;
}

}  // namespace internal
}  // namespace v8