};
-// --- C o u n t e r s C a l l b a c k s
+// --- C o u n t e r s C a l l b a c k s ---
typedef int* (*CounterLookupCallback)(const wchar_t* name);
typedef void (*GCCallback)();
-// --- C o n t e x t G e n e r a t o r
+// --- E x t e r n a l S y m b o l C a l l b a c k ---
+
+/**
+ * Callback used to allocate certain V8 symbols as external strings.
+ *
+ * The data passed to the callback is utf8 encoded.
+ *
+ * Allocations are not allowed in the callback function, you therefore
+ * cannot manipulate objects (set or delete properties for example)
+ * since it is possible such operations will result in the allocation
+ * of objects.
+ */
+typedef String::ExternalStringResource* (*ExternalSymbolCallback)(
+ const char* utf8,
+ size_t length);
+
+
+// --- C o n t e x t G e n e r a t o r ---
/**
* Applications must provide a callback function which is called to generate
static void SetGlobalGCEpilogueCallback(GCCallback);
/**
+ * Applications can register a callback that will be used when
+ * allocating most of the V8 symbols. The callback must return an
+ * external string resource that represents the symbols.
+ *
+ * Most often when performing a property lookup the key will be a
+ * symbol. Allocating symbols as external strings can reduce the
+ * amount of string conversions needed when using interceptors and
+ * accessors.
+ *
+ * \note This is an experimental feature and it might be removed.
+ */
+ static void SetExternalSymbolCallback(ExternalSymbolCallback);
+
+ /**
* Allows the host application to group objects together. If one
* object in the group is alive, all objects in the group are alive.
* After each garbage collection, object groups are removed. It is
}
+void V8::SetExternalSymbolCallback(ExternalSymbolCallback callback) {
+ if (IsDeadCheck("v8::V8::SetExternalSymbolCallback()")) return;
+ i::Heap::SetExternalSymbolCallback(callback);
+}
+
+
String::Utf8Value::Utf8Value(v8::Handle<v8::Value> obj) {
EnsureInitialized("v8::String::Utf8Value::Utf8Value()");
if (obj.IsEmpty()) {
}
+Object* Heap::AllocateSymbol(Vector<const char> str,
+ int chars,
+ uint32_t length_field) {
+ if (global_external_symbol_callback_) {
+ return AllocateExternalSymbol(str, chars);
+ }
+ unibrow::Utf8InputBuffer<> buffer(str.start(),
+ static_cast<unsigned>(str.length()));
+ return AllocateInternalSymbol(&buffer, chars, length_field);
+}
+
+
Object* Heap::AllocateRaw(int size_in_bytes,
AllocationSpace space,
AllocationSpace retry_space) {
GCCallback Heap::global_gc_prologue_callback_ = NULL;
GCCallback Heap::global_gc_epilogue_callback_ = NULL;
+ExternalSymbolCallback Heap::global_external_symbol_callback_ = NULL;
+
// Variables set based on semispace_size_ and old_generation_size_ in
// ConfigureHeap.
int Heap::young_generation_size_ = 0; // Will be 2 * semispace_size_.
}
+Object* Heap::AllocateExternalSymbolFromTwoByte(
+ ExternalTwoByteString::Resource* resource) {
+ Map* map;
+ int length = resource->length();
+ if (length <= String::kMaxShortStringSize) {
+ map = short_external_symbol_map();
+ } else if (length <= String::kMaxMediumStringSize) {
+ map = medium_external_symbol_map();
+ } else {
+ map = long_external_symbol_map();
+ }
+
+ Object* result = Allocate(map, OLD_DATA_SPACE);
+ if (result->IsFailure()) return result;
+
+ ExternalTwoByteString* external_string = ExternalTwoByteString::cast(result);
+ external_string->set_length(length);
+ external_string->set_resource(resource);
+
+ return result;
+}
+
+
Object* Heap::LookupSingleCharacterStringFromCode(uint16_t code) {
if (code <= String::kMaxAsciiCharCode) {
Object* value = Heap::single_character_string_cache()->get(code);
}
-Object* Heap::AllocateSymbol(unibrow::CharacterStream* buffer,
- int chars,
- uint32_t length_field) {
+Object* Heap::AllocateInternalSymbol(unibrow::CharacterStream* buffer,
+ int chars,
+ uint32_t length_field) {
// Ensure the chars matches the number of characters in the buffer.
ASSERT(static_cast<unsigned>(chars) == buffer->Length());
// Determine whether the string is ascii.
}
+// External string resource that only contains a length field. These
+// are used temporarily when allocating external symbols.
+class DummyExternalStringResource
+ : public v8::String::ExternalStringResource {
+ public:
+ explicit DummyExternalStringResource(size_t length) : length_(length) { }
+
+ virtual const uint16_t* data() const {
+ UNREACHABLE();
+ return NULL;
+ }
+
+ virtual size_t length() const { return length_; }
+ private:
+ size_t length_;
+};
+
+
+Object* Heap::AllocateExternalSymbol(Vector<const char> string, int chars) {
+ // Attempt to allocate the resulting external string first. Use a
+ // dummy string resource that has the correct length so that we only
+ // have to patch the external string resource after the callback.
+ DummyExternalStringResource dummy_resource(chars);
+ Object* obj = AllocateExternalSymbolFromTwoByte(&dummy_resource);
+ if (obj->IsFailure()) return obj;
+ // Perform callback.
+ v8::String::ExternalStringResource* resource =
+ global_external_symbol_callback_(string.start(), string.length());
+ // Patch the resource pointer of the result.
+ ExternalTwoByteString* result = ExternalTwoByteString::cast(obj);
+ result->set_resource(resource);
+ ASSERT(result->IsEqualTo(string));
+ return result;
+}
+
+
Object* Heap::AllocateRawAsciiString(int length, PretenureFlag pretenure) {
AllocationSpace space = (pretenure == TENURED) ? OLD_DATA_SPACE : NEW_SPACE;
int size = SeqAsciiString::SizeFor(length);
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this function does not perform a garbage collection.
- static Object* AllocateSymbol(unibrow::CharacterStream* buffer,
- int chars,
- uint32_t length_field);
+ static inline Object* AllocateSymbol(Vector<const char> str,
+ int chars,
+ uint32_t length_field);
+
+ static Object* AllocateInternalSymbol(unibrow::CharacterStream* buffer,
+ int chars,
+ uint32_t length_field);
+
+ static Object* AllocateExternalSymbol(Vector<const char> str,
+ int chars);
+
// Allocates and partially initializes a String. There are two String
// encodings: ASCII and two byte. These functions allocate a string of the
ExternalAsciiString::Resource* resource);
static Object* AllocateExternalStringFromTwoByte(
ExternalTwoByteString::Resource* resource);
+ static Object* AllocateExternalSymbolFromTwoByte(
+ ExternalTwoByteString::Resource* resource);
// Allocates an uninitialized object. The memory is non-executable if the
// hardware and OS allow.
global_gc_epilogue_callback_ = callback;
}
+ static void SetExternalSymbolCallback(ExternalSymbolCallback callback) {
+ global_external_symbol_callback_ = callback;
+ }
+
// Heap roots
#define ROOT_ACCESSOR(type, name) static type* name() { return name##_; }
ROOT_LIST(ROOT_ACCESSOR)
static GCCallback global_gc_prologue_callback_;
static GCCallback global_gc_epilogue_callback_;
+ // Callback function used for allocating external symbols.
+ static ExternalSymbolCallback global_external_symbol_callback_;
+
// Checks whether a global GC is necessary
static GarbageCollector SelectGarbageCollector(AllocationSpace space);
Object* GetObject() {
if (length_field_ == 0) Hash();
- unibrow::Utf8InputBuffer<> buffer(string_.start(),
- static_cast<unsigned>(string_.length()));
- return Heap::AllocateSymbol(&buffer, chars_, length_field_);
+ return Heap::AllocateSymbol(string_, chars_, length_field_);
}
static uint32_t StringHash(Object* obj) {
}
// Otherwise allocate a new symbol.
StringInputBuffer buffer(string_);
- return Heap::AllocateSymbol(&buffer,
- string_->length(),
- string_->length_field());
+ return Heap::AllocateInternalSymbol(&buffer,
+ string_->length(),
+ string_->length_field());
}
static uint32_t StringHash(Object* obj) {
Local<Value> value = CompileRun("obj.x");
CHECK(value->BooleanValue());
}
+
+
+static String::ExternalStringResource* SymbolCallback(const char* chars,
+ size_t length) {
+ uint16_t* buffer = i::NewArray<uint16_t>(length + 1);
+ for (size_t i = 0; i < length; i++) {
+ buffer[i] = chars[i];
+ }
+ buffer[length] = '\0';
+ return new TestResource(buffer);
+}
+
+
+static v8::Handle<Value> ExternalSymbolGetter(Local<String> name,
+ const AccessorInfo& info) {
+ CHECK(name->IsExternal());
+ return v8::True();
+}
+
+
+static void ExternalSymbolSetter(Local<String> name,
+ Local<Value> value,
+ const AccessorInfo&) {
+ CHECK(name->IsExternal());
+}
+
+
+THREADED_TEST(ExternalSymbols) {
+ TestResource::dispose_count = 0;
+ v8::V8::SetExternalSymbolCallback(SymbolCallback);
+ v8::HandleScope scope;
+ LocalContext context;
+ Local<ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetAccessor(v8_str("x"), ExternalSymbolGetter, ExternalSymbolSetter);
+ context->Global()->Set(v8_str("obj"), templ->NewInstance());
+ Local<Value> value = CompileRun("var o = { x: 42 }; o.x");
+ CHECK_EQ(42, value->Int32Value());
+ value = CompileRun("obj.x");
+ CHECK_EQ(true, value->BooleanValue());
+ value = CompileRun("obj.x = 42");
+ v8::V8::SetExternalSymbolCallback(NULL);
+}