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