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
11namespace v8 {
12namespace internal {
13
14template <typename Char, typename Base>
15class SimpleStringResource : public Base {
16 public:
17  // Takes ownership of |data|.
18  SimpleStringResource(Char* data, size_t length)
19      : data_(data),
20        length_(length) {}
21
22  virtual ~SimpleStringResource() { delete[] data_; }
23
24  virtual const Char* data() const { return data_; }
25
26  virtual size_t length() const { return length_; }
27
28 private:
29  Char* const data_;
30  const size_t length_;
31};
32
33
34typedef SimpleStringResource<char, v8::String::ExternalOneByteStringResource>
35    SimpleOneByteStringResource;
36typedef SimpleStringResource<uc16, v8::String::ExternalStringResource>
37    SimpleTwoByteStringResource;
38
39
40const char* const ExternalizeStringExtension::kSource =
41    "native function externalizeString();"
42    "native function isOneByteString();";
43
44v8::Local<v8::FunctionTemplate>
45ExternalizeStringExtension::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
58void 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
126void 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