-
-
Notifications
You must be signed in to change notification settings - Fork 43
Expand file tree
/
Copy pathLazyGlobals.cpp
More file actions
96 lines (82 loc) · 3.51 KB
/
Copy pathLazyGlobals.cpp
File metadata and controls
96 lines (82 loc) · 3.51 KB
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
#include "LazyGlobals.h"
#include "Base64.h"
#include "BuiltinLoader.h"
#include "Helpers.h"
#include "Messaging.h"
#include "StructuredSerialization.h"
#include "TextEncoding.h"
using namespace v8;
namespace tns {
namespace {
// The builtin's `module.exports`, from the single run it gets per isolate
// (BuiltinLoader::GetExports). Two globals out of the same file therefore cost
// one run, and so does a module that exports the same interfaces.
using ExportsAccessor = MaybeLocal<Object> (*)(Local<Context>);
struct LazyGlobalEntry {
const char* name;
const char* exportName; // key of `name` in the builtin's module.exports
ExportsAccessor exports;
};
// Exports accessor for a builtin with no natives of its own; modules with a
// binding (TextEncoding, Base64) own a hand-written accessor instead.
template <BuiltinId id>
MaybeLocal<Object> BuiltinExports(Local<Context> context) {
return BuiltinLoader::GetExports(context, id, nullptr);
}
constexpr LazyGlobalEntry kLazyGlobals[] = {
{"TextEncoder", "TextEncoder", TextEncoding::GetExports},
{"TextDecoder", "TextDecoder", TextEncoding::GetExports},
{"atob", "atob", Base64::GetExports},
{"btoa", "btoa", Base64::GetExports},
{"DOMException", "DOMException", serialization::GetDomExceptionExports},
// events.js is an eager builtin (Events::Init), so this row never runs a
// file: the read hits the exports cache and only the placement is lazy.
{"CustomEvent", "CustomEvent", BuiltinExports<BuiltinId::kEvents>},
{"MessageEvent", "MessageEvent", BuiltinExports<BuiltinId::kMessageEvent>},
{"MessagePort", "MessagePort", messaging::GetMessageChannelExports},
{"MessageChannel", "MessageChannel", messaging::GetMessageChannelExports},
{"BroadcastChannel", "BroadcastChannel",
messaging::GetBroadcastChannelExports},
};
void LazyGlobalGetter(Local<v8::Name> property,
const PropertyCallbackInfo<Value>& info) {
Isolate* isolate = info.GetIsolate();
const auto* entry = static_cast<const LazyGlobalEntry*>(
info.Data().As<External>()->Value(v8::kExternalPointerTypeTagDefault));
Local<Context> context = isolate->GetCurrentContext();
Local<Object> exports;
if (!entry->exports(context).ToLocal(&exports)) {
return;
}
Local<Value> value;
if (!exports->Get(context, tns::ToV8String(isolate, entry->exportName))
.ToLocal(&value)) {
return;
}
info.GetReturnValue().Set(value);
}
} // namespace
void LazyGlobals::Init(Isolate* isolate, Local<ObjectTemplate> globalTemplate) {
for (const LazyGlobalEntry& entry : kLazyGlobals) {
Local<External> data =
External::New(isolate, const_cast<LazyGlobalEntry*>(&entry),
v8::kExternalPointerTypeTagDefault);
// SetLazyDataProperty, not a getter that rewrites the property itself:
// defining over an API accessor reads its current descriptor, which calls
// the getter again and recurses. V8 does the rewrite from the outside, and
// gives a setter-less accessor its ReconfigureToDataProperty setter, so an
// assignment landing before the first read replaces the global as well.
globalTemplate->SetLazyDataProperty(tns::ToV8String(isolate, entry.name),
LazyGlobalGetter, data,
PropertyAttribute::DontEnum);
}
}
bool LazyGlobals::IsLazyGlobal(const std::string& name) {
for (const LazyGlobalEntry& entry : kLazyGlobals) {
if (name == entry.name) {
return true;
}
}
return false;
}
} // namespace tns