1 // Copyright 2010 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/extensions/externalize-string-extension.h"
6
7 #include "src/api.h"
8 #include "src/handles.h"
9 #include "src/isolate.h"
10
11 namespace v8 {
12 namespace internal {
13
14 template <typename Char, typename Base>
15 class SimpleStringResource : public Base {
16 public:
17 // Takes ownership of |data|.
SimpleStringResource(Char * data,size_t length)18 SimpleStringResource(Char* data, size_t length)
19 : data_(data),
20 length_(length) {}
21
~SimpleStringResource()22 virtual ~SimpleStringResource() { delete[] data_; }
23
data() const24 virtual const Char* data() const { return data_; }
25
length() const26 virtual size_t length() const { return length_; }
27
28 private:
29 Char* const data_;
30 const size_t length_;
31 };
32
33
34 typedef SimpleStringResource<char, v8::String::ExternalOneByteStringResource>
35 SimpleOneByteStringResource;
36 typedef SimpleStringResource<uc16, v8::String::ExternalStringResource>
37 SimpleTwoByteStringResource;
38
39
40 const char* const ExternalizeStringExtension::kSource =
41 "native function externalizeString();"
42 "native function isOneByteString();";
43
44 v8::Local<v8::FunctionTemplate>
GetNativeFunctionTemplate(v8::Isolate * isolate,v8::Local<v8::String> str)45 ExternalizeStringExtension::GetNativeFunctionTemplate(
46 v8::Isolate* isolate, v8::Local<v8::String> str) {
47 if (strcmp(*v8::String::Utf8Value(str), "externalizeString") == 0) {
48 return v8::FunctionTemplate::New(isolate,
49 ExternalizeStringExtension::Externalize);
50 } else {
51 DCHECK(strcmp(*v8::String::Utf8Value(str), "isOneByteString") == 0);
52 return v8::FunctionTemplate::New(isolate,
53 ExternalizeStringExtension::IsOneByte);
54 }
55 }
56
57
Externalize(const v8::FunctionCallbackInfo<v8::Value> & args)58 void ExternalizeStringExtension::Externalize(
59 const v8::FunctionCallbackInfo<v8::Value>& args) {
60 if (args.Length() < 1 || !args[0]->IsString()) {
61 args.GetIsolate()->ThrowException(
62 v8::String::NewFromUtf8(
63 args.GetIsolate(),
64 "First parameter to externalizeString() must be a string.",
65 NewStringType::kNormal).ToLocalChecked());
66 return;
67 }
68 bool force_two_byte = false;
69 if (args.Length() >= 2) {
70 if (args[1]->IsBoolean()) {
71 force_two_byte =
72 args[1]
73 ->BooleanValue(args.GetIsolate()->GetCurrentContext())
74 .FromJust();
75 } else {
76 args.GetIsolate()->ThrowException(
77 v8::String::NewFromUtf8(
78 args.GetIsolate(),
79 "Second parameter to externalizeString() must be a boolean.",
80 NewStringType::kNormal).ToLocalChecked());
81 return;
82 }
83 }
84 bool result = false;
85 Handle<String> string = Utils::OpenHandle(*args[0].As<v8::String>());
86 if (string->IsExternalString()) {
87 args.GetIsolate()->ThrowException(
88 v8::String::NewFromUtf8(args.GetIsolate(),
89 "externalizeString() can't externalize twice.",
90 NewStringType::kNormal).ToLocalChecked());
91 return;
92 }
93 if (string->IsOneByteRepresentation() && !force_two_byte) {
94 uint8_t* data = new uint8_t[string->length()];
95 String::WriteToFlat(*string, data, 0, string->length());
96 SimpleOneByteStringResource* resource = new SimpleOneByteStringResource(
97 reinterpret_cast<char*>(data), string->length());
98 result = string->MakeExternal(resource);
99 if (result) {
100 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
101 isolate->heap()->RegisterExternalString(*string);
102 }
103 if (!result) delete resource;
104 } else {
105 uc16* data = new uc16[string->length()];
106 String::WriteToFlat(*string, data, 0, string->length());
107 SimpleTwoByteStringResource* resource = new SimpleTwoByteStringResource(
108 data, string->length());
109 result = string->MakeExternal(resource);
110 if (result) {
111 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
112 isolate->heap()->RegisterExternalString(*string);
113 }
114 if (!result) delete resource;
115 }
116 if (!result) {
117 args.GetIsolate()->ThrowException(
118 v8::String::NewFromUtf8(args.GetIsolate(),
119 "externalizeString() failed.",
120 NewStringType::kNormal).ToLocalChecked());
121 return;
122 }
123 }
124
125
IsOneByte(const v8::FunctionCallbackInfo<v8::Value> & args)126 void ExternalizeStringExtension::IsOneByte(
127 const v8::FunctionCallbackInfo<v8::Value>& args) {
128 if (args.Length() != 1 || !args[0]->IsString()) {
129 args.GetIsolate()->ThrowException(
130 v8::String::NewFromUtf8(
131 args.GetIsolate(),
132 "isOneByteString() requires a single string argument.",
133 NewStringType::kNormal).ToLocalChecked());
134 return;
135 }
136 bool is_one_byte =
137 Utils::OpenHandle(*args[0].As<v8::String>())->IsOneByteRepresentation();
138 args.GetReturnValue().Set(is_one_byte);
139 }
140
141 } // namespace internal
142 } // namespace v8
143