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|. 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 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> 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 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 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