14a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com// Copyright 2010 the V8 project authors. All rights reserved.
23484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// Use of this source code is governed by a BSD-style license that can be
33484964a86451e86dcf04be9bd8c0d76ee04f081rossberg@chromium.org// found in the LICENSE file.
44a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
5196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/extensions/externalize-string-extension.h"
64a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
74a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.comnamespace v8 {
84a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.comnamespace internal {
94a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
104a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.comtemplate <typename Char, typename Base>
114a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.comclass SimpleStringResource : public Base {
124a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com public:
134a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  // Takes ownership of |data|.
144a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  SimpleStringResource(Char* data, size_t length)
154a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com      : data_(data),
164a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com        length_(length) {}
174a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
184a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  virtual ~SimpleStringResource() { delete[] data_; }
194a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
204a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  virtual const Char* data() const { return data_; }
214a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
224a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  virtual size_t length() const { return length_; }
234a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
244a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com private:
254a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  Char* const data_;
264a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  const size_t length_;
274a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com};
284a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
294a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
302c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.orgtypedef SimpleStringResource<char, v8::String::ExternalOneByteStringResource>
312c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org    SimpleOneByteStringResource;
324a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.comtypedef SimpleStringResource<uc16, v8::String::ExternalStringResource>
334a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    SimpleTwoByteStringResource;
344a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
354a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
364a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.comconst char* const ExternalizeStringExtension::kSource =
374a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    "native function externalizeString();"
382c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org    "native function isOneByteString();";
394a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
409f18d9111f676f2899d9aa2444130c985eb75395machenbach@chromium.orgv8::Handle<v8::FunctionTemplate>
419f18d9111f676f2899d9aa2444130c985eb75395machenbach@chromium.orgExternalizeStringExtension::GetNativeFunctionTemplate(
429f18d9111f676f2899d9aa2444130c985eb75395machenbach@chromium.org    v8::Isolate* isolate, v8::Handle<v8::String> str) {
43906e2fb760f52fe6e75b744b1ea42576ea5b2c29ulan@chromium.org  if (strcmp(*v8::String::Utf8Value(str), "externalizeString") == 0) {
444f99be9ff2091451687891a05d99cc31990de709hpayer@chromium.org    return v8::FunctionTemplate::New(isolate,
454f99be9ff2091451687891a05d99cc31990de709hpayer@chromium.org                                     ExternalizeStringExtension::Externalize);
464a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  } else {
472c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org    DCHECK(strcmp(*v8::String::Utf8Value(str), "isOneByteString") == 0);
484f99be9ff2091451687891a05d99cc31990de709hpayer@chromium.org    return v8::FunctionTemplate::New(isolate,
492c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org                                     ExternalizeStringExtension::IsOneByte);
504a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  }
514a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com}
524a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
534a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
54d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.orgvoid ExternalizeStringExtension::Externalize(
55d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org    const v8::FunctionCallbackInfo<v8::Value>& args) {
564a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  if (args.Length() < 1 || !args[0]->IsString()) {
57f9841897146bc10dbb3c45f0632bb79254602c75machenbach@chromium.org    args.GetIsolate()->ThrowException(v8::String::NewFromUtf8(
58f9841897146bc10dbb3c45f0632bb79254602c75machenbach@chromium.org        args.GetIsolate(),
594a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com        "First parameter to externalizeString() must be a string."));
60d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org    return;
614a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  }
624a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  bool force_two_byte = false;
634a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  if (args.Length() >= 2) {
644a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    if (args[1]->IsBoolean()) {
654a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com      force_two_byte = args[1]->BooleanValue();
664a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    } else {
67f9841897146bc10dbb3c45f0632bb79254602c75machenbach@chromium.org      args.GetIsolate()->ThrowException(v8::String::NewFromUtf8(
68f9841897146bc10dbb3c45f0632bb79254602c75machenbach@chromium.org        args.GetIsolate(),
69d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org        "Second parameter to externalizeString() must be a boolean."));
70d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org      return;
714a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    }
724a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  }
734a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  bool result = false;
744a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  Handle<String> string = Utils::OpenHandle(*args[0].As<v8::String>());
754a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  if (string->IsExternalString()) {
76f9841897146bc10dbb3c45f0632bb79254602c75machenbach@chromium.org    args.GetIsolate()->ThrowException(v8::String::NewFromUtf8(
77f9841897146bc10dbb3c45f0632bb79254602c75machenbach@chromium.org        args.GetIsolate(),
784a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com        "externalizeString() can't externalize twice."));
79d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org    return;
804a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  }
818e8d8825f97138de12985f8e0d3163074dff5258ulan@chromium.org  if (string->IsOneByteRepresentation() && !force_two_byte) {
8259297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org    uint8_t* data = new uint8_t[string->length()];
834a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    String::WriteToFlat(*string, data, 0, string->length());
842c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org    SimpleOneByteStringResource* resource = new SimpleOneByteStringResource(
8559297c735ad2a41156ae9c723a39ff259ad061e0jkummerow@chromium.org        reinterpret_cast<char*>(data), string->length());
864a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    result = string->MakeExternal(resource);
87bcc36723a2ace28fa3b0d7dd0d1de926d313fff9machenbach@chromium.org    if (result) {
88c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org      i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
89c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org      isolate->heap()->external_string_table()->AddString(*string);
904a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    }
914a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    if (!result) delete resource;
924a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  } else {
934a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    uc16* data = new uc16[string->length()];
944a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    String::WriteToFlat(*string, data, 0, string->length());
954a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    SimpleTwoByteStringResource* resource = new SimpleTwoByteStringResource(
964a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com        data, string->length());
974a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    result = string->MakeExternal(resource);
98bcc36723a2ace28fa3b0d7dd0d1de926d313fff9machenbach@chromium.org    if (result) {
99c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org      i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
100c5d4971574b7a205fa0e788d8121dc79485e5e67hpayer@chromium.org      isolate->heap()->external_string_table()->AddString(*string);
1014a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    }
1024a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com    if (!result) delete resource;
1034a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  }
1044a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  if (!result) {
105f9841897146bc10dbb3c45f0632bb79254602c75machenbach@chromium.org    args.GetIsolate()->ThrowException(v8::String::NewFromUtf8(
106f9841897146bc10dbb3c45f0632bb79254602c75machenbach@chromium.org        args.GetIsolate(), "externalizeString() failed."));
107d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org    return;
1084a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  }
1094a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com}
1104a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
1114a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
1122c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.orgvoid ExternalizeStringExtension::IsOneByte(
113d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org    const v8::FunctionCallbackInfo<v8::Value>& args) {
1144a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  if (args.Length() != 1 || !args[0]->IsString()) {
115f9841897146bc10dbb3c45f0632bb79254602c75machenbach@chromium.org    args.GetIsolate()->ThrowException(v8::String::NewFromUtf8(
116f9841897146bc10dbb3c45f0632bb79254602c75machenbach@chromium.org        args.GetIsolate(),
1172c81ceb7f1e1ccf5f304be0646f4c1375941a7f2machenbach@chromium.org        "isOneByteString() requires a single string argument."));
118d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org    return;
1194a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com  }
120d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org  bool is_one_byte =
121d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org      Utils::OpenHandle(*args[0].As<v8::String>())->IsOneByteRepresentation();
122d4be0f0c0edfc0a0b46e745055c3dc497c0ffcb5verwaest@chromium.org  args.GetReturnValue().Set(is_one_byte);
1234a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com}
1244a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com
1254a6c3279070e8f133607a74c08d8c08ac394ab98erik.corry@gmail.com} }  // namespace v8::internal
126