Merge the partial_snapshots branch back into bleeding_edge. For
now, the custom call generator stuff is disabled. Review URL: http://codereview.chromium.org/1094014 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4217 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
c2427115db
commit
7d6a3b433f
@ -2683,7 +2683,7 @@ class V8EXPORT Context {
|
||||
|
||||
/** Creates a new context. */
|
||||
static Persistent<Context> New(
|
||||
ExtensionConfiguration* extensions = 0,
|
||||
ExtensionConfiguration* extensions = NULL,
|
||||
Handle<ObjectTemplate> global_template = Handle<ObjectTemplate>(),
|
||||
Handle<Value> global_object = Handle<Value>());
|
||||
|
||||
|
@ -252,12 +252,12 @@ uri.js
|
||||
math.js
|
||||
messages.js
|
||||
apinatives.js
|
||||
debug-delay.js
|
||||
liveedit-delay.js
|
||||
mirror-delay.js
|
||||
date-delay.js
|
||||
regexp-delay.js
|
||||
json-delay.js
|
||||
date.js
|
||||
regexp.js
|
||||
json.js
|
||||
liveedit-debugger.js
|
||||
mirror-debugger.js
|
||||
debug-debugger.js
|
||||
'''.split()
|
||||
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
|
||||
function CreateDate(time) {
|
||||
var date = new ORIGINAL_DATE();
|
||||
var date = new $Date();
|
||||
date.setTime(time);
|
||||
return date;
|
||||
}
|
||||
|
@ -47,21 +47,41 @@ unsigned CpuFeatures::supported_ = 0;
|
||||
unsigned CpuFeatures::enabled_ = 0;
|
||||
unsigned CpuFeatures::found_by_runtime_probing_ = 0;
|
||||
|
||||
|
||||
#ifdef __arm__
|
||||
static uint64_t CpuFeaturesImpliedByCompiler() {
|
||||
uint64_t answer = 0;
|
||||
#ifdef CAN_USE_ARMV7_INSTRUCTIONS
|
||||
answer |= 1u << ARMv7;
|
||||
#endif // def CAN_USE_ARMV7_INSTRUCTIONS
|
||||
// If the compiler is allowed to use VFP then we can use VFP too in our code
|
||||
// generation even when generating snapshots. This won't work for cross
|
||||
// compilation.
|
||||
#if defined(__VFP_FP__) && !defined(__SOFTFP__)
|
||||
answer |= 1u << VFP3;
|
||||
#endif // defined(__VFP_FP__) && !defined(__SOFTFP__)
|
||||
#ifdef CAN_USE_VFP_INSTRUCTIONS
|
||||
answer |= 1u << VFP3;
|
||||
#endif // def CAN_USE_VFP_INSTRUCTIONS
|
||||
return answer;
|
||||
}
|
||||
#endif // def __arm__
|
||||
|
||||
|
||||
void CpuFeatures::Probe() {
|
||||
// If the compiler is allowed to use vfp then we can use vfp too in our
|
||||
// code generation.
|
||||
#if !defined(__arm__)
|
||||
#ifndef __arm__
|
||||
// For the simulator=arm build, use VFP when FLAG_enable_vfp3 is enabled.
|
||||
if (FLAG_enable_vfp3) {
|
||||
supported_ |= 1u << VFP3;
|
||||
supported_ |= 1u << VFP3;
|
||||
}
|
||||
// For the simulator=arm build, use ARMv7 when FLAG_enable_armv7 is enabled
|
||||
if (FLAG_enable_armv7) {
|
||||
supported_ |= 1u << ARMv7;
|
||||
supported_ |= 1u << ARMv7;
|
||||
}
|
||||
#else
|
||||
#else // def __arm__
|
||||
if (Serializer::enabled()) {
|
||||
supported_ |= OS::CpuFeaturesImpliedByPlatform();
|
||||
supported_ |= CpuFeaturesImpliedByCompiler();
|
||||
return; // No features if we might serialize.
|
||||
}
|
||||
|
||||
@ -532,7 +552,7 @@ static bool MustUseIp(RelocInfo::Mode rmode) {
|
||||
if (!Serializer::enabled()) {
|
||||
Serializer::TooLateToEnableNow();
|
||||
}
|
||||
#endif
|
||||
#endif // def DEBUG
|
||||
return Serializer::enabled();
|
||||
} else if (rmode == RelocInfo::NONE) {
|
||||
return false;
|
||||
@ -1137,14 +1157,16 @@ void Assembler::swpb(Register dst,
|
||||
|
||||
// Exception-generating instructions and debugging support.
|
||||
void Assembler::stop(const char* msg) {
|
||||
#if !defined(__arm__)
|
||||
#ifndef __arm__
|
||||
// The simulator handles these special instructions and stops execution.
|
||||
emit(15 << 28 | ((intptr_t) msg));
|
||||
#else
|
||||
// Just issue a simple break instruction for now. Alternatively we could use
|
||||
// the swi(0x9f0001) instruction on Linux.
|
||||
#else // def __arm__
|
||||
#ifdef CAN_USE_ARMV5_INSTRUCTIONS
|
||||
bkpt(0);
|
||||
#endif
|
||||
#else // ndef CAN_USE_ARMV5_INSTRUCTIONS
|
||||
swi(0x9f0001);
|
||||
#endif // ndef CAN_USE_ARMV5_INSTRUCTIONS
|
||||
#endif // def __arm__
|
||||
}
|
||||
|
||||
|
||||
|
@ -122,7 +122,7 @@ void CPU::FlushICache(void* start, size_t size) {
|
||||
|
||||
|
||||
void CPU::DebugBreak() {
|
||||
#if !defined (__arm__)
|
||||
#if !defined (__arm__) || !defined(CAN_USE_ARMV5_INSTRUCTIONS)
|
||||
UNIMPLEMENTED(); // when building ARM emulator target
|
||||
#else
|
||||
asm volatile("bkpt 0");
|
||||
|
@ -145,25 +145,6 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Helper function used to check that a value is either not an object
|
||||
// or is loaded if it is an object.
|
||||
static void GenerateCheckNonObjectOrLoaded(MacroAssembler* masm,
|
||||
Label* miss,
|
||||
Register value,
|
||||
Register scratch) {
|
||||
Label done;
|
||||
// Check if the value is a Smi.
|
||||
__ tst(value, Operand(kSmiTagMask));
|
||||
__ b(eq, &done);
|
||||
// Check if the object has been loaded.
|
||||
__ ldr(scratch, FieldMemOperand(value, JSObject::kMapOffset));
|
||||
__ ldrb(scratch, FieldMemOperand(scratch, Map::kBitField2Offset));
|
||||
__ tst(scratch, Operand(1 << Map::kNeedsLoading));
|
||||
__ b(ne, miss);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void LoadIC::GenerateArrayLength(MacroAssembler* masm) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r2 : name
|
||||
@ -292,12 +273,6 @@ static void GenerateNormalHelper(MacroAssembler* masm,
|
||||
__ CompareObjectType(r1, r0, r0, JS_FUNCTION_TYPE);
|
||||
__ b(ne, miss);
|
||||
|
||||
// Check that the function has been loaded.
|
||||
__ ldr(r0, FieldMemOperand(r1, JSObject::kMapOffset));
|
||||
__ ldrb(r0, FieldMemOperand(r0, Map::kBitField2Offset));
|
||||
__ tst(r0, Operand(1 << Map::kNeedsLoading));
|
||||
__ b(ne, miss);
|
||||
|
||||
// Patch the receiver with the global proxy if necessary.
|
||||
if (is_global_object) {
|
||||
__ ldr(r0, MemOperand(sp, argc * kPointerSize));
|
||||
@ -469,7 +444,6 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||
|
||||
__ bind(&probe);
|
||||
GenerateDictionaryLoad(masm, &miss, r1, r0);
|
||||
GenerateCheckNonObjectOrLoaded(masm, &miss, r0, r1);
|
||||
__ Ret();
|
||||
|
||||
// Global object access: Check access rights.
|
||||
|
@ -923,7 +923,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
// -- lr : return address
|
||||
// -----------------------------------
|
||||
SharedFunctionInfo* function_info = function->shared();
|
||||
if (function_info->HasCustomCallGenerator()) {
|
||||
if (false && function_info->HasCustomCallGenerator()) {
|
||||
CustomCallGenerator generator =
|
||||
ToCData<CustomCallGenerator>(function_info->function_data());
|
||||
return generator(this, object, holder, function, name, check);
|
||||
|
@ -91,7 +91,6 @@ class SourceCodeCache BASE_EMBEDDED {
|
||||
DISALLOW_COPY_AND_ASSIGN(SourceCodeCache);
|
||||
};
|
||||
|
||||
static SourceCodeCache natives_cache(Script::TYPE_NATIVE);
|
||||
static SourceCodeCache extensions_cache(Script::TYPE_EXTENSION);
|
||||
// This is for delete, not delete[].
|
||||
static List<char*>* delete_these_non_arrays_on_tear_down = NULL;
|
||||
@ -134,20 +133,7 @@ Handle<String> Bootstrapper::NativesSourceLookup(int index) {
|
||||
}
|
||||
|
||||
|
||||
bool Bootstrapper::NativesCacheLookup(Vector<const char> name,
|
||||
Handle<SharedFunctionInfo>* handle) {
|
||||
return natives_cache.Lookup(name, handle);
|
||||
}
|
||||
|
||||
|
||||
void Bootstrapper::NativesCacheAdd(Vector<const char> name,
|
||||
Handle<SharedFunctionInfo> fun) {
|
||||
natives_cache.Add(name, fun);
|
||||
}
|
||||
|
||||
|
||||
void Bootstrapper::Initialize(bool create_heap_objects) {
|
||||
natives_cache.Initialize(create_heap_objects);
|
||||
extensions_cache.Initialize(create_heap_objects);
|
||||
}
|
||||
|
||||
@ -187,8 +173,7 @@ void Bootstrapper::TearDown() {
|
||||
delete_these_arrays_on_tear_down = NULL;
|
||||
}
|
||||
|
||||
natives_cache.Initialize(false); // Yes, symmetrical
|
||||
extensions_cache.Initialize(false);
|
||||
extensions_cache.Initialize(false); // Yes, symmetrical
|
||||
}
|
||||
|
||||
|
||||
@ -197,17 +182,11 @@ class Genesis BASE_EMBEDDED {
|
||||
Genesis(Handle<Object> global_object,
|
||||
v8::Handle<v8::ObjectTemplate> global_template,
|
||||
v8::ExtensionConfiguration* extensions);
|
||||
~Genesis();
|
||||
~Genesis() { }
|
||||
|
||||
Handle<Context> result() { return result_; }
|
||||
|
||||
Genesis* previous() { return previous_; }
|
||||
static Genesis* current() { return current_; }
|
||||
|
||||
// Support for thread preemption.
|
||||
static int ArchiveSpacePerThread();
|
||||
static char* ArchiveState(char* to);
|
||||
static char* RestoreState(char* from);
|
||||
|
||||
private:
|
||||
Handle<Context> global_context_;
|
||||
@ -216,18 +195,46 @@ class Genesis BASE_EMBEDDED {
|
||||
// triggered during environment creation there may be weak handle
|
||||
// processing callbacks which may create new environments.
|
||||
Genesis* previous_;
|
||||
static Genesis* current_;
|
||||
|
||||
Handle<Context> global_context() { return global_context_; }
|
||||
|
||||
void CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
|
||||
Handle<Object> global_object);
|
||||
// Creates some basic objects. Used for creating a context from scratch.
|
||||
void CreateRoots();
|
||||
// Creates the empty function. Used for creating a context from scratch.
|
||||
Handle<JSFunction> CreateEmptyFunction();
|
||||
// Creates the global objects using the global and the template passed in
|
||||
// through the API. We call this regardless of whether we are building a
|
||||
// context from scratch or using a deserialized one from the partial snapshot
|
||||
// but in the latter case we don't use the objects it produces directly, as
|
||||
// we have to used the deserialized ones that are linked together with the
|
||||
// rest of the context snapshot.
|
||||
Handle<JSGlobalProxy> CreateNewGlobals(
|
||||
v8::Handle<v8::ObjectTemplate> global_template,
|
||||
Handle<Object> global_object,
|
||||
Handle<GlobalObject>* global_proxy_out);
|
||||
// Hooks the given global proxy into the context. If the context was created
|
||||
// by deserialization then this will unhook the global proxy that was
|
||||
// deserialized, leaving the GC to pick it up.
|
||||
void HookUpGlobalProxy(Handle<GlobalObject> inner_global,
|
||||
Handle<JSGlobalProxy> global_proxy);
|
||||
// Similarly, we want to use the inner global that has been created by the
|
||||
// templates passed through the API. The inner global from the snapshot is
|
||||
// detached from the other objects in the snapshot.
|
||||
void HookUpInnerGlobal(Handle<GlobalObject> inner_global);
|
||||
// New context initialization. Used for creating a context from scratch.
|
||||
void InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
Handle<JSFunction> empty_function);
|
||||
// Installs the contents of the native .js files on the global objects.
|
||||
// Used for creating a context from scratch.
|
||||
void InstallNativeFunctions();
|
||||
bool InstallNatives();
|
||||
bool InstallExtensions(v8::ExtensionConfiguration* extensions);
|
||||
bool InstallExtension(const char* name);
|
||||
bool InstallExtension(v8::RegisteredExtension* current);
|
||||
bool InstallSpecialObjects();
|
||||
// Used both for deserialized and from-scratch contexts to add the extensions
|
||||
// provided.
|
||||
static bool InstallExtensions(Handle<Context> global_context,
|
||||
v8::ExtensionConfiguration* extensions);
|
||||
static bool InstallExtension(const char* name);
|
||||
static bool InstallExtension(v8::RegisteredExtension* current);
|
||||
static void InstallSpecialObjects(Handle<Context> global_context);
|
||||
bool InstallJSBuiltins(Handle<JSBuiltinsObject> builtins);
|
||||
bool ConfigureApiObject(Handle<JSObject> object,
|
||||
Handle<ObjectTemplateInfo> object_template);
|
||||
@ -251,33 +258,36 @@ class Genesis BASE_EMBEDDED {
|
||||
Handle<String> source,
|
||||
SourceCodeCache* cache,
|
||||
v8::Extension* extension,
|
||||
Handle<Context> top_context,
|
||||
bool use_runtime_context);
|
||||
|
||||
Handle<Context> result_;
|
||||
Handle<JSFunction> empty_function_;
|
||||
BootstrapperActive active_;
|
||||
friend class Bootstrapper;
|
||||
};
|
||||
|
||||
Genesis* Genesis::current_ = NULL;
|
||||
|
||||
|
||||
void Bootstrapper::Iterate(ObjectVisitor* v) {
|
||||
natives_cache.Iterate(v);
|
||||
v->Synchronize("NativesCache");
|
||||
extensions_cache.Iterate(v);
|
||||
v->Synchronize("Extensions");
|
||||
}
|
||||
|
||||
|
||||
bool Bootstrapper::IsActive() {
|
||||
return Genesis::current() != NULL;
|
||||
}
|
||||
|
||||
|
||||
Handle<Context> Bootstrapper::CreateEnvironment(
|
||||
Handle<Object> global_object,
|
||||
v8::Handle<v8::ObjectTemplate> global_template,
|
||||
v8::ExtensionConfiguration* extensions) {
|
||||
HandleScope scope;
|
||||
Handle<Context> env;
|
||||
Genesis genesis(global_object, global_template, extensions);
|
||||
return genesis.result();
|
||||
env = genesis.result();
|
||||
if (!env.is_null()) {
|
||||
if (InstallExtensions(env, extensions)) {
|
||||
return env;
|
||||
}
|
||||
}
|
||||
return Handle<Context>();
|
||||
}
|
||||
|
||||
|
||||
@ -299,12 +309,6 @@ void Bootstrapper::DetachGlobal(Handle<Context> env) {
|
||||
}
|
||||
|
||||
|
||||
Genesis::~Genesis() {
|
||||
ASSERT(current_ == this);
|
||||
current_ = previous_;
|
||||
}
|
||||
|
||||
|
||||
static Handle<JSFunction> InstallFunction(Handle<JSObject> target,
|
||||
const char* name,
|
||||
InstanceType type,
|
||||
@ -384,22 +388,7 @@ Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
|
||||
}
|
||||
|
||||
|
||||
void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
|
||||
Handle<Object> global_object) {
|
||||
HandleScope scope;
|
||||
// Allocate the global context FixedArray first and then patch the
|
||||
// closure and extension object later (we need the empty function
|
||||
// and the global object, but in order to create those, we need the
|
||||
// global context).
|
||||
global_context_ =
|
||||
Handle<Context>::cast(
|
||||
GlobalHandles::Create(*Factory::NewGlobalContext()));
|
||||
Top::set_context(*global_context());
|
||||
|
||||
// Allocate the message listeners object.
|
||||
v8::NeanderArray listeners;
|
||||
global_context()->set_message_listeners(*listeners.value());
|
||||
|
||||
Handle<JSFunction> Genesis::CreateEmptyFunction() {
|
||||
// Allocate the map for function instances.
|
||||
Handle<Map> fm = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
|
||||
global_context()->set_function_instance_map(*fm);
|
||||
@ -443,138 +432,196 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
|
||||
Handle<JSFunction> empty_function =
|
||||
Factory::NewFunction(symbol, Factory::null_value());
|
||||
|
||||
{ // --- E m p t y ---
|
||||
Handle<Code> code =
|
||||
Handle<Code>(Builtins::builtin(Builtins::EmptyFunction));
|
||||
empty_function->set_code(*code);
|
||||
Handle<String> source = Factory::NewStringFromAscii(CStrVector("() {}"));
|
||||
Handle<Script> script = Factory::NewScript(source);
|
||||
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
|
||||
empty_function->shared()->set_script(*script);
|
||||
empty_function->shared()->set_start_position(0);
|
||||
empty_function->shared()->set_end_position(source->length());
|
||||
empty_function->shared()->DontAdaptArguments();
|
||||
global_context()->function_map()->set_prototype(*empty_function);
|
||||
global_context()->function_instance_map()->set_prototype(*empty_function);
|
||||
// --- E m p t y ---
|
||||
Handle<Code> code =
|
||||
Handle<Code>(Builtins::builtin(Builtins::EmptyFunction));
|
||||
empty_function->set_code(*code);
|
||||
Handle<String> source = Factory::NewStringFromAscii(CStrVector("() {}"));
|
||||
Handle<Script> script = Factory::NewScript(source);
|
||||
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
|
||||
empty_function->shared()->set_script(*script);
|
||||
empty_function->shared()->set_start_position(0);
|
||||
empty_function->shared()->set_end_position(source->length());
|
||||
empty_function->shared()->DontAdaptArguments();
|
||||
global_context()->function_map()->set_prototype(*empty_function);
|
||||
global_context()->function_instance_map()->set_prototype(*empty_function);
|
||||
|
||||
// Allocate the function map first and then patch the prototype later
|
||||
Handle<Map> empty_fm = Factory::CopyMapDropDescriptors(fm);
|
||||
empty_fm->set_instance_descriptors(*function_map_descriptors);
|
||||
empty_fm->set_prototype(global_context()->object_function()->prototype());
|
||||
empty_function->set_map(*empty_fm);
|
||||
// Allocate the function map first and then patch the prototype later
|
||||
Handle<Map> empty_fm = Factory::CopyMapDropDescriptors(fm);
|
||||
empty_fm->set_instance_descriptors(*function_map_descriptors);
|
||||
empty_fm->set_prototype(global_context()->object_function()->prototype());
|
||||
empty_function->set_map(*empty_fm);
|
||||
return empty_function;
|
||||
}
|
||||
|
||||
|
||||
void Genesis::CreateRoots() {
|
||||
// Allocate the global context FixedArray first and then patch the
|
||||
// closure and extension object later (we need the empty function
|
||||
// and the global object, but in order to create those, we need the
|
||||
// global context).
|
||||
global_context_ =
|
||||
Handle<Context>::cast(
|
||||
GlobalHandles::Create(*Factory::NewGlobalContext()));
|
||||
Top::set_context(*global_context());
|
||||
|
||||
// Allocate the message listeners object.
|
||||
{
|
||||
v8::NeanderArray listeners;
|
||||
global_context()->set_message_listeners(*listeners.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Handle<JSGlobalProxy> Genesis::CreateNewGlobals(
|
||||
v8::Handle<v8::ObjectTemplate> global_template,
|
||||
Handle<Object> global_object,
|
||||
Handle<GlobalObject>* inner_global_out) {
|
||||
// The argument global_template aka data is an ObjectTemplateInfo.
|
||||
// It has a constructor pointer that points at global_constructor which is a
|
||||
// FunctionTemplateInfo.
|
||||
// The global_constructor is used to create or reinitialize the global_proxy.
|
||||
// The global_constructor also has a prototype_template pointer that points at
|
||||
// js_global_template which is an ObjectTemplateInfo.
|
||||
// That in turn has a constructor pointer that points at
|
||||
// js_global_constructor which is a FunctionTemplateInfo.
|
||||
// js_global_constructor is used to make js_global_function
|
||||
// js_global_function is used to make the new inner_global.
|
||||
//
|
||||
// --- G l o b a l ---
|
||||
// Step 1: Create a fresh inner JSGlobalObject.
|
||||
Handle<JSFunction> js_global_function;
|
||||
Handle<ObjectTemplateInfo> js_global_template;
|
||||
if (!global_template.IsEmpty()) {
|
||||
// Get prototype template of the global_template.
|
||||
Handle<ObjectTemplateInfo> data =
|
||||
v8::Utils::OpenHandle(*global_template);
|
||||
Handle<FunctionTemplateInfo> global_constructor =
|
||||
Handle<FunctionTemplateInfo>(
|
||||
FunctionTemplateInfo::cast(data->constructor()));
|
||||
Handle<Object> proto_template(global_constructor->prototype_template());
|
||||
if (!proto_template->IsUndefined()) {
|
||||
js_global_template =
|
||||
Handle<ObjectTemplateInfo>::cast(proto_template);
|
||||
}
|
||||
}
|
||||
|
||||
{ // --- G l o b a l ---
|
||||
// Step 1: create a fresh inner JSGlobalObject
|
||||
Handle<GlobalObject> object;
|
||||
{
|
||||
Handle<JSFunction> js_global_function;
|
||||
Handle<ObjectTemplateInfo> js_global_template;
|
||||
if (!global_template.IsEmpty()) {
|
||||
// Get prototype template of the global_template
|
||||
Handle<ObjectTemplateInfo> data =
|
||||
v8::Utils::OpenHandle(*global_template);
|
||||
Handle<FunctionTemplateInfo> global_constructor =
|
||||
Handle<FunctionTemplateInfo>(
|
||||
FunctionTemplateInfo::cast(data->constructor()));
|
||||
Handle<Object> proto_template(global_constructor->prototype_template());
|
||||
if (!proto_template->IsUndefined()) {
|
||||
js_global_template =
|
||||
Handle<ObjectTemplateInfo>::cast(proto_template);
|
||||
}
|
||||
}
|
||||
|
||||
if (js_global_template.is_null()) {
|
||||
Handle<String> name = Handle<String>(Heap::empty_symbol());
|
||||
Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
|
||||
js_global_function =
|
||||
Factory::NewFunction(name, JS_GLOBAL_OBJECT_TYPE,
|
||||
JSGlobalObject::kSize, code, true);
|
||||
// Change the constructor property of the prototype of the
|
||||
// hidden global function to refer to the Object function.
|
||||
Handle<JSObject> prototype =
|
||||
Handle<JSObject>(
|
||||
JSObject::cast(js_global_function->instance_prototype()));
|
||||
SetProperty(prototype, Factory::constructor_symbol(),
|
||||
Top::object_function(), NONE);
|
||||
} else {
|
||||
Handle<FunctionTemplateInfo> js_global_constructor(
|
||||
FunctionTemplateInfo::cast(js_global_template->constructor()));
|
||||
js_global_function =
|
||||
Factory::CreateApiFunction(js_global_constructor,
|
||||
Factory::InnerGlobalObject);
|
||||
}
|
||||
|
||||
js_global_function->initial_map()->set_is_hidden_prototype();
|
||||
object = Factory::NewGlobalObject(js_global_function);
|
||||
}
|
||||
|
||||
// Set the global context for the global object.
|
||||
object->set_global_context(*global_context());
|
||||
|
||||
// Step 2: create or re-initialize the global proxy object.
|
||||
Handle<JSGlobalProxy> global_proxy;
|
||||
{
|
||||
Handle<JSFunction> global_proxy_function;
|
||||
if (global_template.IsEmpty()) {
|
||||
Handle<String> name = Handle<String>(Heap::empty_symbol());
|
||||
Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
|
||||
global_proxy_function =
|
||||
Factory::NewFunction(name, JS_GLOBAL_PROXY_TYPE,
|
||||
JSGlobalProxy::kSize, code, true);
|
||||
} else {
|
||||
Handle<ObjectTemplateInfo> data =
|
||||
v8::Utils::OpenHandle(*global_template);
|
||||
Handle<FunctionTemplateInfo> global_constructor(
|
||||
FunctionTemplateInfo::cast(data->constructor()));
|
||||
global_proxy_function =
|
||||
Factory::CreateApiFunction(global_constructor,
|
||||
Factory::OuterGlobalObject);
|
||||
}
|
||||
|
||||
Handle<String> global_name = Factory::LookupAsciiSymbol("global");
|
||||
global_proxy_function->shared()->set_instance_class_name(*global_name);
|
||||
global_proxy_function->initial_map()->set_is_access_check_needed(true);
|
||||
|
||||
// Set global_proxy.__proto__ to js_global after ConfigureGlobalObjects
|
||||
|
||||
if (global_object.location() != NULL) {
|
||||
ASSERT(global_object->IsJSGlobalProxy());
|
||||
global_proxy =
|
||||
ReinitializeJSGlobalProxy(
|
||||
global_proxy_function,
|
||||
Handle<JSGlobalProxy>::cast(global_object));
|
||||
} else {
|
||||
global_proxy = Handle<JSGlobalProxy>::cast(
|
||||
Factory::NewJSObject(global_proxy_function, TENURED));
|
||||
}
|
||||
|
||||
// Security setup: Set the security token of the global object to
|
||||
// its the inner global. This makes the security check between two
|
||||
// different contexts fail by default even in case of global
|
||||
// object reinitialization.
|
||||
object->set_global_receiver(*global_proxy);
|
||||
global_proxy->set_context(*global_context());
|
||||
}
|
||||
|
||||
{ // --- G l o b a l C o n t e x t ---
|
||||
// use the empty function as closure (no scope info)
|
||||
global_context()->set_closure(*empty_function);
|
||||
global_context()->set_fcontext(*global_context());
|
||||
global_context()->set_previous(NULL);
|
||||
|
||||
// set extension and global object
|
||||
global_context()->set_extension(*object);
|
||||
global_context()->set_global(*object);
|
||||
global_context()->set_global_proxy(*global_proxy);
|
||||
// use inner global object as security token by default
|
||||
global_context()->set_security_token(*object);
|
||||
}
|
||||
|
||||
Handle<JSObject> global = Handle<JSObject>(global_context()->global());
|
||||
SetProperty(global, object_name, Top::object_function(), DONT_ENUM);
|
||||
if (js_global_template.is_null()) {
|
||||
Handle<String> name = Handle<String>(Heap::empty_symbol());
|
||||
Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
|
||||
js_global_function =
|
||||
Factory::NewFunction(name, JS_GLOBAL_OBJECT_TYPE,
|
||||
JSGlobalObject::kSize, code, true);
|
||||
// Change the constructor property of the prototype of the
|
||||
// hidden global function to refer to the Object function.
|
||||
Handle<JSObject> prototype =
|
||||
Handle<JSObject>(
|
||||
JSObject::cast(js_global_function->instance_prototype()));
|
||||
SetProperty(prototype, Factory::constructor_symbol(),
|
||||
Top::object_function(), NONE);
|
||||
} else {
|
||||
Handle<FunctionTemplateInfo> js_global_constructor(
|
||||
FunctionTemplateInfo::cast(js_global_template->constructor()));
|
||||
js_global_function =
|
||||
Factory::CreateApiFunction(js_global_constructor,
|
||||
Factory::InnerGlobalObject);
|
||||
}
|
||||
|
||||
js_global_function->initial_map()->set_is_hidden_prototype();
|
||||
Handle<GlobalObject> inner_global =
|
||||
Factory::NewGlobalObject(js_global_function);
|
||||
if (inner_global_out != NULL) {
|
||||
*inner_global_out = inner_global;
|
||||
}
|
||||
|
||||
// Step 2: create or re-initialize the global proxy object.
|
||||
Handle<JSFunction> global_proxy_function;
|
||||
if (global_template.IsEmpty()) {
|
||||
Handle<String> name = Handle<String>(Heap::empty_symbol());
|
||||
Handle<Code> code = Handle<Code>(Builtins::builtin(Builtins::Illegal));
|
||||
global_proxy_function =
|
||||
Factory::NewFunction(name, JS_GLOBAL_PROXY_TYPE,
|
||||
JSGlobalProxy::kSize, code, true);
|
||||
} else {
|
||||
Handle<ObjectTemplateInfo> data =
|
||||
v8::Utils::OpenHandle(*global_template);
|
||||
Handle<FunctionTemplateInfo> global_constructor(
|
||||
FunctionTemplateInfo::cast(data->constructor()));
|
||||
global_proxy_function =
|
||||
Factory::CreateApiFunction(global_constructor,
|
||||
Factory::OuterGlobalObject);
|
||||
}
|
||||
|
||||
Handle<String> global_name = Factory::LookupAsciiSymbol("global");
|
||||
global_proxy_function->shared()->set_instance_class_name(*global_name);
|
||||
global_proxy_function->initial_map()->set_is_access_check_needed(true);
|
||||
|
||||
// Set global_proxy.__proto__ to js_global after ConfigureGlobalObjects
|
||||
// Return the global proxy.
|
||||
|
||||
if (global_object.location() != NULL) {
|
||||
ASSERT(global_object->IsJSGlobalProxy());
|
||||
return ReinitializeJSGlobalProxy(
|
||||
global_proxy_function,
|
||||
Handle<JSGlobalProxy>::cast(global_object));
|
||||
} else {
|
||||
return Handle<JSGlobalProxy>::cast(
|
||||
Factory::NewJSObject(global_proxy_function, TENURED));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Genesis::HookUpGlobalProxy(Handle<GlobalObject> inner_global,
|
||||
Handle<JSGlobalProxy> global_proxy) {
|
||||
// Set the global context for the global object.
|
||||
inner_global->set_global_context(*global_context());
|
||||
inner_global->set_global_receiver(*global_proxy);
|
||||
global_proxy->set_context(*global_context());
|
||||
global_context()->set_global_proxy(*global_proxy);
|
||||
}
|
||||
|
||||
|
||||
void Genesis::HookUpInnerGlobal(Handle<GlobalObject> inner_global) {
|
||||
Handle<GlobalObject> inner_global_from_snapshot(
|
||||
GlobalObject::cast(global_context_->extension()));
|
||||
Handle<JSBuiltinsObject> builtins_global(global_context_->builtins());
|
||||
global_context_->set_extension(*inner_global);
|
||||
global_context_->set_global(*inner_global);
|
||||
global_context_->set_security_token(*inner_global);
|
||||
static const PropertyAttributes attributes =
|
||||
static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
|
||||
ForceSetProperty(builtins_global,
|
||||
Factory::LookupAsciiSymbol("global"),
|
||||
inner_global,
|
||||
attributes);
|
||||
// Setup the reference from the global object to the builtins object.
|
||||
JSGlobalObject::cast(*inner_global)->set_builtins(*builtins_global);
|
||||
TransferNamedProperties(inner_global_from_snapshot, inner_global);
|
||||
TransferIndexedProperties(inner_global_from_snapshot, inner_global);
|
||||
}
|
||||
|
||||
|
||||
// This is only called if we are not using snapshots. The equivalent
|
||||
// work in the snapshot case is done in HookUpInnerGlobal.
|
||||
void Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
Handle<JSFunction> empty_function) {
|
||||
// --- G l o b a l C o n t e x t ---
|
||||
// Use the empty function as closure (no scope info).
|
||||
global_context()->set_closure(*empty_function);
|
||||
global_context()->set_fcontext(*global_context());
|
||||
global_context()->set_previous(NULL);
|
||||
// Set extension and global object.
|
||||
global_context()->set_extension(*inner_global);
|
||||
global_context()->set_global(*inner_global);
|
||||
// Security setup: Set the security token of the global object to
|
||||
// its the inner global. This makes the security check between two
|
||||
// different contexts fail by default even in case of global
|
||||
// object reinitialization.
|
||||
global_context()->set_security_token(*inner_global);
|
||||
|
||||
Handle<String> object_name = Handle<String>(Heap::Object_symbol());
|
||||
SetProperty(inner_global, object_name, Top::object_function(), DONT_ENUM);
|
||||
|
||||
Handle<JSObject> global = Handle<JSObject>(global_context()->global());
|
||||
|
||||
// Install global Function object
|
||||
@ -791,8 +838,12 @@ bool Genesis::CompileNative(Vector<const char> name, Handle<String> source) {
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
Debugger::set_compiling_natives(true);
|
||||
#endif
|
||||
bool result =
|
||||
CompileScriptCached(name, source, &natives_cache, NULL, true);
|
||||
bool result = CompileScriptCached(name,
|
||||
source,
|
||||
NULL,
|
||||
NULL,
|
||||
Handle<Context>(Top::context()),
|
||||
true);
|
||||
ASSERT(Top::has_pending_exception() != result);
|
||||
if (!result) Top::clear_pending_exception();
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
@ -806,13 +857,14 @@ bool Genesis::CompileScriptCached(Vector<const char> name,
|
||||
Handle<String> source,
|
||||
SourceCodeCache* cache,
|
||||
v8::Extension* extension,
|
||||
Handle<Context> top_context,
|
||||
bool use_runtime_context) {
|
||||
HandleScope scope;
|
||||
Handle<SharedFunctionInfo> function_info;
|
||||
|
||||
// If we can't find the function in the cache, we compile a new
|
||||
// function and insert it into the cache.
|
||||
if (!cache->Lookup(name, &function_info)) {
|
||||
if (cache == NULL || !cache->Lookup(name, &function_info)) {
|
||||
ASSERT(source->IsAsciiRepresentation());
|
||||
Handle<String> script_name = Factory::NewStringFromUtf8(name);
|
||||
function_info = Compiler::Compile(
|
||||
@ -825,17 +877,17 @@ bool Genesis::CompileScriptCached(Vector<const char> name,
|
||||
Handle<String>::null(),
|
||||
use_runtime_context ? NATIVES_CODE : NOT_NATIVES_CODE);
|
||||
if (function_info.is_null()) return false;
|
||||
cache->Add(name, function_info);
|
||||
if (cache != NULL) cache->Add(name, function_info);
|
||||
}
|
||||
|
||||
// Setup the function context. Conceptually, we should clone the
|
||||
// function before overwriting the context but since we're in a
|
||||
// single-threaded environment it is not strictly necessary.
|
||||
ASSERT(Top::context()->IsGlobalContext());
|
||||
ASSERT(top_context->IsGlobalContext());
|
||||
Handle<Context> context =
|
||||
Handle<Context>(use_runtime_context
|
||||
? Top::context()->runtime_context()
|
||||
: Top::context());
|
||||
? Handle<Context>(top_context->runtime_context())
|
||||
: top_context);
|
||||
Handle<JSFunction> fun =
|
||||
Factory::NewFunctionFromSharedFunctionInfo(function_info, context);
|
||||
|
||||
@ -843,8 +895,8 @@ bool Genesis::CompileScriptCached(Vector<const char> name,
|
||||
// object as the receiver. Provide no parameters.
|
||||
Handle<Object> receiver =
|
||||
Handle<Object>(use_runtime_context
|
||||
? Top::context()->builtins()
|
||||
: Top::context()->global());
|
||||
? top_context->builtins()
|
||||
: top_context->global());
|
||||
bool has_pending_exception;
|
||||
Handle<Object> result =
|
||||
Execution::Call(fun, receiver, 0, NULL, &has_pending_exception);
|
||||
@ -1046,7 +1098,7 @@ bool Genesis::InstallNatives() {
|
||||
// Allocate the empty script.
|
||||
Handle<Script> script = Factory::NewScript(Factory::empty_string());
|
||||
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
|
||||
global_context()->set_empty_script(*script);
|
||||
Heap::public_set_empty_script(*script);
|
||||
}
|
||||
{
|
||||
// Builtin function for OpaqueReference -- a JSValue-based object,
|
||||
@ -1062,46 +1114,16 @@ bool Genesis::InstallNatives() {
|
||||
global_context()->set_opaque_reference_function(*opaque_reference_fun);
|
||||
}
|
||||
|
||||
if (FLAG_natives_file == NULL) {
|
||||
// Without natives file, install default natives.
|
||||
for (int i = Natives::GetDelayCount();
|
||||
i < Natives::GetBuiltinsCount();
|
||||
i++) {
|
||||
if (!CompileBuiltin(i)) return false;
|
||||
// TODO(ager): We really only need to install the JS builtin
|
||||
// functions on the builtins object after compiling and running
|
||||
// runtime.js.
|
||||
if (!InstallJSBuiltins(builtins)) return false;
|
||||
}
|
||||
|
||||
// Setup natives with lazy loading.
|
||||
SetupLazy(Handle<JSFunction>(global_context()->date_function()),
|
||||
Natives::GetIndex("date"),
|
||||
Top::global_context(),
|
||||
Handle<Context>(Top::context()->runtime_context()));
|
||||
SetupLazy(Handle<JSFunction>(global_context()->regexp_function()),
|
||||
Natives::GetIndex("regexp"),
|
||||
Top::global_context(),
|
||||
Handle<Context>(Top::context()->runtime_context()));
|
||||
SetupLazy(Handle<JSObject>(global_context()->json_object()),
|
||||
Natives::GetIndex("json"),
|
||||
Top::global_context(),
|
||||
Handle<Context>(Top::context()->runtime_context()));
|
||||
|
||||
} else if (strlen(FLAG_natives_file) != 0) {
|
||||
// Otherwise install natives from natives file if file exists and
|
||||
// compiles.
|
||||
bool exists;
|
||||
Vector<const char> source = ReadFile(FLAG_natives_file, &exists);
|
||||
Handle<String> source_string = Factory::NewStringFromAscii(source);
|
||||
if (source.is_empty()) return false;
|
||||
bool result = CompileNative(CStrVector(FLAG_natives_file), source_string);
|
||||
if (!result) return false;
|
||||
|
||||
} else {
|
||||
// Empty natives file name - do not install any natives.
|
||||
PrintF("Warning: Running without installed natives!\n");
|
||||
return true;
|
||||
// Install natives.
|
||||
for (int i = Natives::GetDebuggerCount();
|
||||
i < Natives::GetBuiltinsCount();
|
||||
i++) {
|
||||
Vector<const char> name = Natives::GetScriptName(i);
|
||||
if (!CompileBuiltin(i)) return false;
|
||||
// TODO(ager): We really only need to install the JS builtin
|
||||
// functions on the builtins object after compiling and running
|
||||
// runtime.js.
|
||||
if (!InstallJSBuiltins(builtins)) return false;
|
||||
}
|
||||
|
||||
InstallNativeFunctions();
|
||||
@ -1142,14 +1164,29 @@ bool Genesis::InstallNatives() {
|
||||
#ifdef DEBUG
|
||||
builtins->Verify();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Genesis::InstallSpecialObjects() {
|
||||
int BootstrapperActive::nesting_ = 0;
|
||||
|
||||
|
||||
bool Bootstrapper::InstallExtensions(Handle<Context> global_context,
|
||||
v8::ExtensionConfiguration* extensions) {
|
||||
BootstrapperActive active;
|
||||
SaveContext saved_context;
|
||||
Top::set_context(*global_context);
|
||||
if (!Genesis::InstallExtensions(global_context, extensions)) return false;
|
||||
Genesis::InstallSpecialObjects(global_context);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void Genesis::InstallSpecialObjects(Handle<Context> global_context) {
|
||||
HandleScope scope;
|
||||
Handle<JSGlobalObject> js_global(
|
||||
JSGlobalObject::cast(global_context()->global()));
|
||||
JSGlobalObject::cast(global_context->global()));
|
||||
// Expose the natives in global if a name for it is specified.
|
||||
if (FLAG_expose_natives_as != NULL && strlen(FLAG_expose_natives_as) != 0) {
|
||||
Handle<String> natives_string =
|
||||
@ -1172,13 +1209,12 @@ bool Genesis::InstallSpecialObjects() {
|
||||
if (FLAG_expose_debug_as != NULL && strlen(FLAG_expose_debug_as) != 0) {
|
||||
// If loading fails we just bail out without installing the
|
||||
// debugger but without tanking the whole context.
|
||||
if (!Debug::Load())
|
||||
return true;
|
||||
if (!Debug::Load()) return;
|
||||
// Set the security token for the debugger context to the same as
|
||||
// the shell global context to allow calling between these (otherwise
|
||||
// exposing debug global object doesn't make much sense).
|
||||
Debug::debug_context()->set_security_token(
|
||||
global_context()->security_token());
|
||||
global_context->security_token());
|
||||
|
||||
Handle<String> debug_string =
|
||||
Factory::LookupAsciiSymbol(FLAG_expose_debug_as);
|
||||
@ -1186,19 +1222,18 @@ bool Genesis::InstallSpecialObjects() {
|
||||
Handle<Object>(Debug::debug_context()->global_proxy()), DONT_ENUM);
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Genesis::InstallExtensions(v8::ExtensionConfiguration* extensions) {
|
||||
bool Genesis::InstallExtensions(Handle<Context> global_context,
|
||||
v8::ExtensionConfiguration* extensions) {
|
||||
// Clear coloring of extension list
|
||||
v8::RegisteredExtension* current = v8::RegisteredExtension::first_extension();
|
||||
while (current != NULL) {
|
||||
current->set_state(v8::UNVISITED);
|
||||
current = current->next();
|
||||
}
|
||||
// Install auto extensions
|
||||
// Install auto extensions.
|
||||
current = v8::RegisteredExtension::first_extension();
|
||||
while (current != NULL) {
|
||||
if (current->extension()->auto_enable())
|
||||
@ -1262,7 +1297,9 @@ bool Genesis::InstallExtension(v8::RegisteredExtension* current) {
|
||||
Handle<String> source_code = Factory::NewStringFromAscii(source);
|
||||
bool result = CompileScriptCached(CStrVector(extension->name()),
|
||||
source_code,
|
||||
&extensions_cache, extension,
|
||||
&extensions_cache,
|
||||
extension,
|
||||
Handle<Context>(Top::context()),
|
||||
false);
|
||||
ASSERT(Top::has_pending_exception() != result);
|
||||
if (!result) {
|
||||
@ -1293,7 +1330,7 @@ bool Genesis::ConfigureGlobalObjects(
|
||||
v8::Handle<v8::ObjectTemplate> global_proxy_template) {
|
||||
Handle<JSObject> global_proxy(
|
||||
JSObject::cast(global_context()->global_proxy()));
|
||||
Handle<JSObject> js_global(JSObject::cast(global_context()->global()));
|
||||
Handle<JSObject> inner_global(JSObject::cast(global_context()->global()));
|
||||
|
||||
if (!global_proxy_template.IsEmpty()) {
|
||||
// Configure the global proxy object.
|
||||
@ -1307,11 +1344,11 @@ bool Genesis::ConfigureGlobalObjects(
|
||||
if (!proxy_constructor->prototype_template()->IsUndefined()) {
|
||||
Handle<ObjectTemplateInfo> inner_data(
|
||||
ObjectTemplateInfo::cast(proxy_constructor->prototype_template()));
|
||||
if (!ConfigureApiObject(js_global, inner_data)) return false;
|
||||
if (!ConfigureApiObject(inner_global, inner_data)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
SetObjectPrototype(global_proxy, js_global);
|
||||
SetObjectPrototype(global_proxy, inner_global);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1365,15 +1402,13 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
|
||||
// If the property is already there we skip it
|
||||
if (result.IsProperty()) continue;
|
||||
HandleScope inner;
|
||||
Handle<DescriptorArray> inst_descs =
|
||||
Handle<DescriptorArray>(to->map()->instance_descriptors());
|
||||
ASSERT(!to->HasFastProperties());
|
||||
// Add to dictionary.
|
||||
Handle<String> key = Handle<String>(descs->GetKey(i));
|
||||
Handle<Object> entry = Handle<Object>(descs->GetCallbacksObject(i));
|
||||
inst_descs = Factory::CopyAppendProxyDescriptor(inst_descs,
|
||||
key,
|
||||
entry,
|
||||
details.attributes());
|
||||
to->map()->set_instance_descriptors(*inst_descs);
|
||||
Handle<Object> callbacks(descs->GetCallbacksObject(i));
|
||||
PropertyDetails d =
|
||||
PropertyDetails(details.attributes(), CALLBACKS, details.index());
|
||||
SetNormalizedProperty(to, key, callbacks, d);
|
||||
break;
|
||||
}
|
||||
case MAP_TRANSITION:
|
||||
@ -1458,32 +1493,51 @@ void Genesis::MakeFunctionInstancePrototypeWritable() {
|
||||
Genesis::Genesis(Handle<Object> global_object,
|
||||
v8::Handle<v8::ObjectTemplate> global_template,
|
||||
v8::ExtensionConfiguration* extensions) {
|
||||
// Link this genesis object into the stacked genesis chain. This
|
||||
// must be done before any early exits because the destructor
|
||||
// will always do unlinking.
|
||||
previous_ = current_;
|
||||
current_ = this;
|
||||
result_ = Handle<Context>::null();
|
||||
|
||||
// If V8 isn't running and cannot be initialized, just return.
|
||||
if (!V8::IsRunning() && !V8::Initialize(NULL)) return;
|
||||
|
||||
// Before creating the roots we must save the context and restore it
|
||||
// on all function exits.
|
||||
HandleScope scope;
|
||||
SaveContext context;
|
||||
SaveContext saved_context;
|
||||
|
||||
CreateRoots(global_template, global_object);
|
||||
Handle<Context> new_context = Snapshot::NewContextFromSnapshot();
|
||||
if (!new_context.is_null()) {
|
||||
global_context_ =
|
||||
Handle<Context>::cast(GlobalHandles::Create(*new_context));
|
||||
Top::set_context(*global_context_);
|
||||
i::Counters::contexts_created_by_snapshot.Increment();
|
||||
result_ = global_context_;
|
||||
JSFunction* empty_function =
|
||||
JSFunction::cast(result_->function_map()->prototype());
|
||||
empty_function_ = Handle<JSFunction>(empty_function);
|
||||
Handle<GlobalObject> inner_global;
|
||||
Handle<JSGlobalProxy> global_proxy =
|
||||
CreateNewGlobals(global_template,
|
||||
global_object,
|
||||
&inner_global);
|
||||
|
||||
if (!InstallNatives()) return;
|
||||
HookUpGlobalProxy(inner_global, global_proxy);
|
||||
HookUpInnerGlobal(inner_global);
|
||||
|
||||
MakeFunctionInstancePrototypeWritable();
|
||||
if (!ConfigureGlobalObjects(global_template)) return;
|
||||
} else {
|
||||
// We get here if there was no context snapshot.
|
||||
CreateRoots();
|
||||
Handle<JSFunction> empty_function = CreateEmptyFunction();
|
||||
Handle<GlobalObject> inner_global;
|
||||
Handle<JSGlobalProxy> global_proxy =
|
||||
CreateNewGlobals(global_template, global_object, &inner_global);
|
||||
HookUpGlobalProxy(inner_global, global_proxy);
|
||||
InitializeGlobal(inner_global, empty_function);
|
||||
if (!InstallNatives()) return;
|
||||
|
||||
if (!ConfigureGlobalObjects(global_template)) return;
|
||||
MakeFunctionInstancePrototypeWritable();
|
||||
|
||||
if (!InstallExtensions(extensions)) return;
|
||||
|
||||
if (!InstallSpecialObjects()) return;
|
||||
if (!ConfigureGlobalObjects(global_template)) return;
|
||||
i::Counters::contexts_created_from_scratch.Increment();
|
||||
}
|
||||
|
||||
result_ = global_context_;
|
||||
}
|
||||
@ -1493,46 +1547,46 @@ Genesis::Genesis(Handle<Object> global_object,
|
||||
|
||||
// Reserve space for statics needing saving and restoring.
|
||||
int Bootstrapper::ArchiveSpacePerThread() {
|
||||
return Genesis::ArchiveSpacePerThread();
|
||||
return BootstrapperActive::ArchiveSpacePerThread();
|
||||
}
|
||||
|
||||
|
||||
// Archive statics that are thread local.
|
||||
char* Bootstrapper::ArchiveState(char* to) {
|
||||
return Genesis::ArchiveState(to);
|
||||
return BootstrapperActive::ArchiveState(to);
|
||||
}
|
||||
|
||||
|
||||
// Restore statics that are thread local.
|
||||
char* Bootstrapper::RestoreState(char* from) {
|
||||
return Genesis::RestoreState(from);
|
||||
return BootstrapperActive::RestoreState(from);
|
||||
}
|
||||
|
||||
|
||||
// Called when the top-level V8 mutex is destroyed.
|
||||
void Bootstrapper::FreeThreadResources() {
|
||||
ASSERT(Genesis::current() == NULL);
|
||||
ASSERT(!BootstrapperActive::IsActive());
|
||||
}
|
||||
|
||||
|
||||
// Reserve space for statics needing saving and restoring.
|
||||
int Genesis::ArchiveSpacePerThread() {
|
||||
return sizeof(current_);
|
||||
int BootstrapperActive::ArchiveSpacePerThread() {
|
||||
return sizeof(nesting_);
|
||||
}
|
||||
|
||||
|
||||
// Archive statics that are thread local.
|
||||
char* Genesis::ArchiveState(char* to) {
|
||||
*reinterpret_cast<Genesis**>(to) = current_;
|
||||
current_ = NULL;
|
||||
return to + sizeof(current_);
|
||||
char* BootstrapperActive::ArchiveState(char* to) {
|
||||
*reinterpret_cast<int*>(to) = nesting_;
|
||||
nesting_ = 0;
|
||||
return to + sizeof(nesting_);
|
||||
}
|
||||
|
||||
|
||||
// Restore statics that are thread local.
|
||||
char* Genesis::RestoreState(char* from) {
|
||||
current_ = *reinterpret_cast<Genesis**>(from);
|
||||
return from + sizeof(current_);
|
||||
char* BootstrapperActive::RestoreState(char* from) {
|
||||
nesting_ = *reinterpret_cast<int*>(from);
|
||||
return from + sizeof(nesting_);
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -32,6 +32,24 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
class BootstrapperActive BASE_EMBEDDED {
|
||||
public:
|
||||
BootstrapperActive() { nesting_++; }
|
||||
~BootstrapperActive() { nesting_--; }
|
||||
|
||||
// Support for thread preemption.
|
||||
static int ArchiveSpacePerThread();
|
||||
static char* ArchiveState(char* to);
|
||||
static char* RestoreState(char* from);
|
||||
|
||||
private:
|
||||
static bool IsActive() { return nesting_ != 0; }
|
||||
static int nesting_;
|
||||
friend class Bootstrapper;
|
||||
};
|
||||
|
||||
|
||||
// The Boostrapper is the public interface for creating a JavaScript global
|
||||
// context.
|
||||
class Bootstrapper : public AllStatic {
|
||||
@ -53,15 +71,11 @@ class Bootstrapper : public AllStatic {
|
||||
// Traverses the pointers for memory management.
|
||||
static void Iterate(ObjectVisitor* v);
|
||||
|
||||
// Accessors for the native scripts cache. Used in lazy loading.
|
||||
// Accessor for the native scripts source code.
|
||||
static Handle<String> NativesSourceLookup(int index);
|
||||
static bool NativesCacheLookup(Vector<const char> name,
|
||||
Handle<SharedFunctionInfo>* handle);
|
||||
static void NativesCacheAdd(Vector<const char> name,
|
||||
Handle<SharedFunctionInfo> fun);
|
||||
|
||||
// Tells whether bootstrapping is active.
|
||||
static bool IsActive();
|
||||
static bool IsActive() { return BootstrapperActive::IsActive(); }
|
||||
|
||||
// Encoding/decoding support for fixup flags.
|
||||
class FixupFlagsUseCodeObject: public BitField<bool, 0, 1> {};
|
||||
@ -76,6 +90,10 @@ class Bootstrapper : public AllStatic {
|
||||
// This will allocate a char array that is deleted when V8 is shut down.
|
||||
// It should only be used for strictly finite allocations.
|
||||
static char* AllocateAutoDeletedArray(int bytes);
|
||||
|
||||
// Used for new context creation.
|
||||
static bool InstallExtensions(Handle<Context> global_context,
|
||||
v8::ExtensionConfiguration* extensions);
|
||||
};
|
||||
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "v8.h"
|
||||
|
||||
#include "compilation-cache.h"
|
||||
#include "serialize.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
@ -86,7 +86,6 @@ enum ContextLookupFlags {
|
||||
V(CALL_AS_FUNCTION_DELEGATE_INDEX, JSFunction, call_as_function_delegate) \
|
||||
V(CALL_AS_CONSTRUCTOR_DELEGATE_INDEX, JSFunction, \
|
||||
call_as_constructor_delegate) \
|
||||
V(EMPTY_SCRIPT_INDEX, Script, empty_script) \
|
||||
V(SCRIPT_FUNCTION_INDEX, JSFunction, script_function) \
|
||||
V(OPAQUE_REFERENCE_FUNCTION_INDEX, JSFunction, opaque_reference_function) \
|
||||
V(CONTEXT_EXTENSION_FUNCTION_INDEX, JSFunction, context_extension_function) \
|
||||
@ -207,7 +206,6 @@ class Context: public FixedArray {
|
||||
RUNTIME_CONTEXT_INDEX,
|
||||
CALL_AS_FUNCTION_DELEGATE_INDEX,
|
||||
CALL_AS_CONSTRUCTOR_DELEGATE_INDEX,
|
||||
EMPTY_SCRIPT_INDEX,
|
||||
SCRIPT_FUNCTION_INDEX,
|
||||
OPAQUE_REFERENCE_FUNCTION_INDEX,
|
||||
CONTEXT_EXTENSION_FUNCTION_INDEX,
|
||||
|
@ -720,7 +720,6 @@ bool Debug::CompileDebuggerScript(int index) {
|
||||
|
||||
// Mark this script as native and return successfully.
|
||||
Handle<Script> script(Script::cast(function->shared()->script()));
|
||||
script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1682,7 +1681,7 @@ void Debug::CreateScriptCache() {
|
||||
|
||||
// Perform two GCs to get rid of all unreferenced scripts. The first GC gets
|
||||
// rid of all the cached script wrappers and the second gets rid of the
|
||||
// scripts which is no longer referenced.
|
||||
// scripts which are no longer referenced.
|
||||
Heap::CollectAllGarbage(false);
|
||||
Heap::CollectAllGarbage(false);
|
||||
|
||||
@ -1996,7 +1995,7 @@ void Debugger::OnAfterCompile(Handle<Script> script,
|
||||
// If debugging there might be script break points registered for this
|
||||
// script. Make sure that these break points are set.
|
||||
|
||||
// Get the function UpdateScriptBreakPoints (defined in debug-delay.js).
|
||||
// Get the function UpdateScriptBreakPoints (defined in debug-debugger.js).
|
||||
Handle<Object> update_script_break_points =
|
||||
Handle<Object>(Debug::debug_context()->global()->GetProperty(
|
||||
*Factory::LookupAsciiSymbol("UpdateScriptBreakPoints")));
|
||||
|
@ -122,7 +122,6 @@ DEFINE_bool(enable_armv7, true,
|
||||
// bootstrapper.cc
|
||||
DEFINE_string(expose_natives_as, NULL, "expose natives in global object")
|
||||
DEFINE_string(expose_debug_as, NULL, "expose debug in global object")
|
||||
DEFINE_string(natives_file, NULL, "alternative natives file")
|
||||
DEFINE_bool(expose_gc, false, "expose gc extension")
|
||||
DEFINE_int(stack_trace_limit, 10, "number of stack frames to capture")
|
||||
|
||||
|
@ -346,6 +346,7 @@ void StackFrame::UncookFramesForThread(ThreadLocalTop* thread) {
|
||||
|
||||
void StackFrame::Cook() {
|
||||
Code* code = this->code();
|
||||
ASSERT(code->IsCode());
|
||||
for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
|
||||
it.handler()->Cook(code);
|
||||
}
|
||||
@ -356,6 +357,7 @@ void StackFrame::Cook() {
|
||||
|
||||
void StackFrame::Uncook() {
|
||||
Code* code = this->code();
|
||||
ASSERT(code->IsCode());
|
||||
for (StackHandlerIterator it(this, top_handler()); !it.done(); it.Advance()) {
|
||||
it.handler()->Uncook(code);
|
||||
}
|
||||
|
@ -325,7 +325,6 @@ enum Executability { NOT_EXECUTABLE, EXECUTABLE };
|
||||
|
||||
enum VisitMode { VISIT_ALL, VISIT_ALL_IN_SCAVENGE, VISIT_ONLY_STRONG };
|
||||
|
||||
|
||||
// Flag indicating whether code is built into the VM (one of the natives files).
|
||||
enum NativesFlag { NOT_NATIVES_CODE, NATIVES_CODE };
|
||||
|
||||
@ -408,7 +407,7 @@ enum CallFunctionFlags {
|
||||
// Type of properties.
|
||||
// Order of properties is significant.
|
||||
// Must fit in the BitField PropertyDetails::TypeField.
|
||||
// A copy of this is in mirror-delay.js.
|
||||
// A copy of this is in mirror-debugger.js.
|
||||
enum PropertyType {
|
||||
NORMAL = 0, // only in slow mode
|
||||
FIELD = 1, // only in fast mode
|
||||
|
@ -236,6 +236,15 @@ Handle<Object> ForceSetProperty(Handle<JSObject> object,
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
|
||||
Handle<String> key,
|
||||
Handle<Object> value,
|
||||
PropertyDetails details) {
|
||||
CALL_HEAP_FUNCTION(object->SetNormalizedProperty(*key, *value, details),
|
||||
Object);
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
|
||||
Handle<Object> key) {
|
||||
CALL_HEAP_FUNCTION(Runtime::ForceDeleteObjectProperty(object, key), Object);
|
||||
@ -777,92 +786,4 @@ OptimizedObjectForAddingMultipleProperties::
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LoadLazy(Handle<JSObject> obj, bool* pending_exception) {
|
||||
HandleScope scope;
|
||||
Handle<FixedArray> info(FixedArray::cast(obj->map()->constructor()));
|
||||
int index = Smi::cast(info->get(0))->value();
|
||||
ASSERT(index >= 0);
|
||||
Handle<Context> compile_context(Context::cast(info->get(1)));
|
||||
Handle<Context> function_context(Context::cast(info->get(2)));
|
||||
Handle<Object> receiver(compile_context->global()->builtins());
|
||||
|
||||
Vector<const char> name = Natives::GetScriptName(index);
|
||||
|
||||
Handle<SharedFunctionInfo> function_info;
|
||||
|
||||
if (!Bootstrapper::NativesCacheLookup(name, &function_info)) {
|
||||
Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
|
||||
Handle<String> script_name = Factory::NewStringFromAscii(name);
|
||||
bool allow_natives_syntax = FLAG_allow_natives_syntax;
|
||||
FLAG_allow_natives_syntax = true;
|
||||
function_info = Compiler::Compile(source_code,
|
||||
script_name,
|
||||
0, 0, NULL, NULL,
|
||||
Handle<String>::null(),
|
||||
NATIVES_CODE);
|
||||
FLAG_allow_natives_syntax = allow_natives_syntax;
|
||||
// If the compilation failed (possibly due to stack overflows), we
|
||||
// should never enter the result in the natives cache. Instead we
|
||||
// return from the function without marking the function as having
|
||||
// been lazily loaded.
|
||||
if (function_info.is_null()) {
|
||||
*pending_exception = true;
|
||||
return;
|
||||
}
|
||||
Bootstrapper::NativesCacheAdd(name, function_info);
|
||||
}
|
||||
|
||||
// We shouldn't get here if compiling the script failed.
|
||||
ASSERT(!function_info.is_null());
|
||||
|
||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||
// When the debugger running in its own context touches lazy loaded
|
||||
// functions loading can be triggered. In that case ensure that the
|
||||
// execution of the boilerplate is in the correct context.
|
||||
SaveContext save;
|
||||
if (!Debug::debug_context().is_null() &&
|
||||
Top::context() == *Debug::debug_context()) {
|
||||
Top::set_context(*compile_context);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Reset the lazy load data before running the script to make sure
|
||||
// not to get recursive lazy loading.
|
||||
obj->map()->set_needs_loading(false);
|
||||
obj->map()->set_constructor(info->get(3));
|
||||
|
||||
// Run the script.
|
||||
Handle<JSFunction> script_fun(
|
||||
Factory::NewFunctionFromSharedFunctionInfo(function_info,
|
||||
function_context));
|
||||
Execution::Call(script_fun, receiver, 0, NULL, pending_exception);
|
||||
|
||||
// If lazy loading failed, restore the unloaded state of obj.
|
||||
if (*pending_exception) {
|
||||
obj->map()->set_needs_loading(true);
|
||||
obj->map()->set_constructor(*info);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SetupLazy(Handle<JSObject> obj,
|
||||
int index,
|
||||
Handle<Context> compile_context,
|
||||
Handle<Context> function_context) {
|
||||
Handle<FixedArray> arr = Factory::NewFixedArray(4);
|
||||
arr->set(0, Smi::FromInt(index));
|
||||
arr->set(1, *compile_context); // Compile in this context
|
||||
arr->set(2, *function_context); // Set function context to this
|
||||
arr->set(3, obj->map()->constructor()); // Remember the constructor
|
||||
Handle<Map> old_map(obj->map());
|
||||
Handle<Map> new_map = Factory::CopyMapDropTransitions(old_map);
|
||||
obj->set_map(*new_map);
|
||||
new_map->set_needs_loading(true);
|
||||
// Store the lazy loading info in the constructor field. We'll
|
||||
// reestablish the constructor from the fixed array after loading.
|
||||
new_map->set_constructor(*arr);
|
||||
ASSERT(!obj->IsLoaded());
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -210,6 +210,11 @@ Handle<Object> ForceSetProperty(Handle<JSObject> object,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
Handle<Object> SetNormalizedProperty(Handle<JSObject> object,
|
||||
Handle<String> key,
|
||||
Handle<Object> value,
|
||||
PropertyDetails details);
|
||||
|
||||
Handle<Object> ForceDeleteProperty(Handle<JSObject> object,
|
||||
Handle<Object> key);
|
||||
|
||||
@ -338,13 +343,6 @@ bool CompileLazyInLoop(Handle<JSFunction> function,
|
||||
// Returns the lazy compilation stub for argc arguments.
|
||||
Handle<Code> ComputeLazyCompile(int argc);
|
||||
|
||||
// These deal with lazily loaded properties.
|
||||
void SetupLazy(Handle<JSObject> obj,
|
||||
int index,
|
||||
Handle<Context> compile_context,
|
||||
Handle<Context> function_context);
|
||||
void LoadLazy(Handle<JSObject> obj, bool* pending_exception);
|
||||
|
||||
class NoHandleAllocation BASE_EMBEDDED {
|
||||
public:
|
||||
#ifndef DEBUG
|
||||
|
@ -108,6 +108,7 @@ class ZoneScopeInfo;
|
||||
V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \
|
||||
V(FixedArray, natives_source_cache, NativesSourceCache) \
|
||||
V(Object, last_script_id, LastScriptId) \
|
||||
V(Script, empty_script, EmptyScript) \
|
||||
V(Smi, real_stack_limit, RealStackLimit) \
|
||||
|
||||
#if V8_TARGET_ARCH_ARM && V8_NATIVE_REGEXP
|
||||
@ -758,6 +759,10 @@ class Heap : public AllStatic {
|
||||
roots_[kNonMonomorphicCacheRootIndex] = value;
|
||||
}
|
||||
|
||||
static void public_set_empty_script(Script* script) {
|
||||
roots_[kEmptyScriptRootIndex] = script;
|
||||
}
|
||||
|
||||
// Update the next script id.
|
||||
static inline void SetLastScriptId(Object* last_script_id);
|
||||
|
||||
|
@ -254,23 +254,6 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Helper function used to check that a value is either not an object
|
||||
// or is loaded if it is an object.
|
||||
static void GenerateCheckNonObjectOrLoaded(MacroAssembler* masm, Label* miss,
|
||||
Register value, Register scratch) {
|
||||
Label done;
|
||||
// Check if the value is a Smi.
|
||||
__ test(value, Immediate(kSmiTagMask));
|
||||
__ j(zero, &done, not_taken);
|
||||
// Check if the object has been loaded.
|
||||
__ mov(scratch, FieldOperand(value, JSFunction::kMapOffset));
|
||||
__ mov(scratch, FieldOperand(scratch, Map::kBitField2Offset));
|
||||
__ test(scratch, Immediate(1 << Map::kNeedsLoading));
|
||||
__ j(not_zero, miss, not_taken);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
// The offset from the inlined patch site to the start of the
|
||||
// inlined load instruction. It is 7 bytes (test eax, imm) plus
|
||||
// 6 bytes (jne slow_label).
|
||||
@ -495,7 +478,6 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
ecx,
|
||||
edi,
|
||||
DICTIONARY_CHECK_DONE);
|
||||
GenerateCheckNonObjectOrLoaded(masm, &slow, ecx, ebx);
|
||||
__ mov(eax, ecx);
|
||||
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
|
||||
__ ret(0);
|
||||
@ -1146,11 +1128,6 @@ static void GenerateNormalHelper(MacroAssembler* masm,
|
||||
__ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
|
||||
__ j(not_equal, miss, not_taken);
|
||||
|
||||
// Check that the function has been loaded. eax holds function's map.
|
||||
__ mov(eax, FieldOperand(eax, Map::kBitField2Offset));
|
||||
__ test(eax, Immediate(1 << Map::kNeedsLoading));
|
||||
__ j(not_zero, miss, not_taken);
|
||||
|
||||
// Patch the receiver on stack with the global proxy if necessary.
|
||||
if (is_global_object) {
|
||||
__ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
|
||||
@ -1341,7 +1318,6 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||
edi,
|
||||
ebx,
|
||||
CHECK_DICTIONARY);
|
||||
GenerateCheckNonObjectOrLoaded(masm, &miss, edi, edx);
|
||||
__ mov(eax, edi);
|
||||
__ ret(0);
|
||||
|
||||
|
@ -1454,7 +1454,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
// -----------------------------------
|
||||
|
||||
SharedFunctionInfo* function_info = function->shared();
|
||||
if (function_info->HasCustomCallGenerator()) {
|
||||
if (false && function_info->HasCustomCallGenerator()) {
|
||||
CustomCallGenerator generator =
|
||||
ToCData<CustomCallGenerator>(function_info->function_data());
|
||||
return generator(this, object, holder, function, name, check);
|
||||
|
17
src/ic.cc
17
src/ic.cc
@ -436,7 +436,7 @@ Object* CallIC::LoadFunction(State state,
|
||||
}
|
||||
|
||||
// Lookup is valid: Update inline cache and stub cache.
|
||||
if (FLAG_use_ic && lookup.IsLoaded()) {
|
||||
if (FLAG_use_ic) {
|
||||
UpdateCaches(&lookup, state, object, name);
|
||||
}
|
||||
|
||||
@ -484,7 +484,6 @@ void CallIC::UpdateCaches(LookupResult* lookup,
|
||||
State state,
|
||||
Handle<Object> object,
|
||||
Handle<String> name) {
|
||||
ASSERT(lookup->IsLoaded());
|
||||
// Bail out if we didn't find a result.
|
||||
if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
|
||||
|
||||
@ -647,7 +646,6 @@ Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
|
||||
FLAG_use_ic &&
|
||||
state == PREMONOMORPHIC &&
|
||||
lookup.IsProperty() &&
|
||||
lookup.IsLoaded() &&
|
||||
lookup.IsCacheable() &&
|
||||
lookup.holder() == *object &&
|
||||
lookup.type() == FIELD &&
|
||||
@ -669,7 +667,7 @@ Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) {
|
||||
}
|
||||
|
||||
// Update inline cache and stub cache.
|
||||
if (FLAG_use_ic && lookup.IsLoaded()) {
|
||||
if (FLAG_use_ic) {
|
||||
UpdateCaches(&lookup, state, object, name);
|
||||
}
|
||||
|
||||
@ -695,7 +693,6 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
|
||||
State state,
|
||||
Handle<Object> object,
|
||||
Handle<String> name) {
|
||||
ASSERT(lookup->IsLoaded());
|
||||
// Bail out if we didn't find a result.
|
||||
if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
|
||||
|
||||
@ -857,7 +854,7 @@ Object* KeyedLoadIC::Load(State state,
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_use_ic && lookup.IsLoaded()) {
|
||||
if (FLAG_use_ic) {
|
||||
UpdateCaches(&lookup, state, object, name);
|
||||
}
|
||||
|
||||
@ -912,7 +909,6 @@ Object* KeyedLoadIC::Load(State state,
|
||||
|
||||
void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
|
||||
Handle<Object> object, Handle<String> name) {
|
||||
ASSERT(lookup->IsLoaded());
|
||||
// Bail out if we didn't find a result.
|
||||
if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
|
||||
|
||||
@ -993,8 +989,6 @@ static bool StoreICableLookup(LookupResult* lookup) {
|
||||
// state.
|
||||
if (lookup->IsReadOnly()) return false;
|
||||
|
||||
if (!lookup->IsLoaded()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1073,7 +1067,6 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<String> name,
|
||||
Handle<Object> value) {
|
||||
ASSERT(lookup->IsLoaded());
|
||||
// Skip JSGlobalProxy.
|
||||
ASSERT(!receiver->IsJSGlobalProxy());
|
||||
|
||||
@ -1181,7 +1174,7 @@ Object* KeyedStoreIC::Store(State state,
|
||||
receiver->LocalLookup(*name, &lookup);
|
||||
|
||||
// Update inline cache and stub cache.
|
||||
if (FLAG_use_ic && lookup.IsLoaded()) {
|
||||
if (FLAG_use_ic) {
|
||||
UpdateCaches(&lookup, state, receiver, name, value);
|
||||
}
|
||||
|
||||
@ -1215,8 +1208,6 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
|
||||
Handle<JSObject> receiver,
|
||||
Handle<String> name,
|
||||
Handle<Object> value) {
|
||||
ASSERT(lookup->IsLoaded());
|
||||
|
||||
// Skip JSGlobalProxy.
|
||||
if (receiver->IsJSGlobalProxy()) return;
|
||||
|
||||
|
@ -66,11 +66,6 @@ Handle<Object> RegExpImpl::CreateRegExpLiteral(Handle<JSFunction> constructor,
|
||||
Handle<String> pattern,
|
||||
Handle<String> flags,
|
||||
bool* has_pending_exception) {
|
||||
// Ensure that the constructor function has been loaded.
|
||||
if (!constructor->IsLoaded()) {
|
||||
LoadLazy(constructor, has_pending_exception);
|
||||
if (*has_pending_exception) return Handle<Object>();
|
||||
}
|
||||
// Call the construct code with 2 arguments.
|
||||
Object** argv[2] = { Handle<Object>::cast(pattern).location(),
|
||||
Handle<Object>::cast(flags).location() };
|
||||
|
431
src/liveedit-debugger.js
Normal file
431
src/liveedit-debugger.js
Normal file
@ -0,0 +1,431 @@
|
||||
// Copyright 2010 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// LiveEdit feature implementation. The script should be executed after
|
||||
// debug-debugger.js.
|
||||
|
||||
|
||||
// Changes script text and recompiles all relevant functions if possible.
|
||||
// The change is always a substring (change_pos, change_pos + change_len)
|
||||
// being replaced with a completely different string new_str.
|
||||
//
|
||||
// Only one function will have its Code changed in result of this function.
|
||||
// All nested functions (should they have any instances at the moment) are left
|
||||
// unchanged and re-linked to a newly created script instance representing old
|
||||
// version of the source. (Generally speaking,
|
||||
// during the change all nested functions are erased and completely different
|
||||
// set of nested functions are introduced.) All other functions just have
|
||||
// their positions updated.
|
||||
//
|
||||
// @param {Script} script that is being changed
|
||||
// @param {Array} change_log a list that collects engineer-readable description
|
||||
// of what happened.
|
||||
Debug.LiveEditChangeScript = function(script, change_pos, change_len, new_str,
|
||||
change_log) {
|
||||
|
||||
// So far the function works as namespace.
|
||||
var liveedit = Debug.LiveEditChangeScript;
|
||||
var Assert = liveedit.Assert;
|
||||
|
||||
// Fully compiles source string as a script. Returns Array of
|
||||
// FunctionCompileInfo -- a descriptions of all functions of the script.
|
||||
// Elements of array are ordered by start positions of functions (from top
|
||||
// to bottom) in the source. Fields outer_index and next_sibling_index help
|
||||
// to navigate the nesting structure of functions.
|
||||
//
|
||||
// The script is used for compilation, because it produces code that
|
||||
// needs to be linked with some particular script (for nested functions).
|
||||
function DebugGatherCompileInfo(source) {
|
||||
// Get function info, elements are partially sorted (it is a tree
|
||||
// of nested functions serialized as parent followed by serialized children.
|
||||
var raw_compile_info = %LiveEditGatherCompileInfo(script, source);
|
||||
|
||||
// Sort function infos by start position field.
|
||||
var compile_info = new Array();
|
||||
var old_index_map = new Array();
|
||||
for (var i = 0; i < raw_compile_info.length; i++) {
|
||||
compile_info.push(new liveedit.FunctionCompileInfo(raw_compile_info[i]));
|
||||
old_index_map.push(i);
|
||||
}
|
||||
|
||||
for (var i = 0; i < compile_info.length; i++) {
|
||||
var k = i;
|
||||
for (var j = i + 1; j < compile_info.length; j++) {
|
||||
if (compile_info[k].start_position > compile_info[j].start_position) {
|
||||
k = j;
|
||||
}
|
||||
}
|
||||
if (k != i) {
|
||||
var temp_info = compile_info[k];
|
||||
var temp_index = old_index_map[k];
|
||||
compile_info[k] = compile_info[i];
|
||||
old_index_map[k] = old_index_map[i];
|
||||
compile_info[i] = temp_info;
|
||||
old_index_map[i] = temp_index;
|
||||
}
|
||||
}
|
||||
|
||||
// After sorting update outer_inder field using old_index_map. Also
|
||||
// set next_sibling_index field.
|
||||
var current_index = 0;
|
||||
|
||||
// The recursive function, that goes over all children of a particular
|
||||
// node (i.e. function info).
|
||||
function ResetIndexes(new_parent_index, old_parent_index) {
|
||||
var previous_sibling = -1;
|
||||
while (current_index < compile_info.length &&
|
||||
compile_info[current_index].outer_index == old_parent_index) {
|
||||
var saved_index = current_index;
|
||||
compile_info[saved_index].outer_index = new_parent_index;
|
||||
if (previous_sibling != -1) {
|
||||
compile_info[previous_sibling].next_sibling_index = saved_index;
|
||||
}
|
||||
previous_sibling = saved_index;
|
||||
current_index++;
|
||||
ResetIndexes(saved_index, old_index_map[saved_index]);
|
||||
}
|
||||
if (previous_sibling != -1) {
|
||||
compile_info[previous_sibling].next_sibling_index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
ResetIndexes(-1, -1);
|
||||
Assert(current_index == compile_info.length);
|
||||
|
||||
return compile_info;
|
||||
}
|
||||
|
||||
// Given a positions, finds a function that fully includes the entire change.
|
||||
function FindChangedFunction(compile_info, offset, len) {
|
||||
// First condition: function should start before the change region.
|
||||
// Function #0 (whole-script function) always does, but we want
|
||||
// one, that is later in this list.
|
||||
var index = 0;
|
||||
while (index + 1 < compile_info.length &&
|
||||
compile_info[index + 1].start_position <= offset) {
|
||||
index++;
|
||||
}
|
||||
// Now we are at the last function that begins before the change
|
||||
// region. The function that covers entire change region is either
|
||||
// this function or the enclosing one.
|
||||
for (; compile_info[index].end_position < offset + len;
|
||||
index = compile_info[index].outer_index) {
|
||||
Assert(index != -1);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
// Variable forward declarations. Preprocessor "Minifier" needs them.
|
||||
var old_compile_info;
|
||||
var shared_infos;
|
||||
// Finds SharedFunctionInfo that corresponds compile info with index
|
||||
// in old version of the script.
|
||||
function FindFunctionInfo(index) {
|
||||
var old_info = old_compile_info[index];
|
||||
for (var i = 0; i < shared_infos.length; i++) {
|
||||
var info = shared_infos[i];
|
||||
if (info.start_position == old_info.start_position &&
|
||||
info.end_position == old_info.end_position) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Replaces function's Code.
|
||||
function PatchCode(new_info, shared_info) {
|
||||
%LiveEditReplaceFunctionCode(new_info.raw_array, shared_info.raw_array);
|
||||
|
||||
change_log.push( {function_patched: new_info.function_name} );
|
||||
}
|
||||
|
||||
var change_len_old;
|
||||
var change_len_new;
|
||||
// Translate position in old version of script into position in new
|
||||
// version of script.
|
||||
function PosTranslator(old_pos) {
|
||||
if (old_pos <= change_pos) {
|
||||
return old_pos;
|
||||
}
|
||||
if (old_pos >= change_pos + change_len_old) {
|
||||
return old_pos + change_len_new - change_len_old;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
var position_change_array;
|
||||
var position_patch_report;
|
||||
function PatchPositions(new_info, shared_info) {
|
||||
if (!shared_info) {
|
||||
// TODO: explain what is happening.
|
||||
return;
|
||||
}
|
||||
%LiveEditPatchFunctionPositions(shared_info.raw_array,
|
||||
position_change_array);
|
||||
position_patch_report.push( { name: new_info.function_name } );
|
||||
}
|
||||
|
||||
var link_to_old_script_report;
|
||||
var old_script;
|
||||
// Makes a function associated with another instance of a script (the
|
||||
// one representing its old version). This way the function still
|
||||
// may access its own text.
|
||||
function LinkToOldScript(shared_info) {
|
||||
%LiveEditRelinkFunctionToScript(shared_info.raw_array, old_script);
|
||||
|
||||
link_to_old_script_report.push( { name: shared_info.function_name } );
|
||||
}
|
||||
|
||||
|
||||
|
||||
var old_source = script.source;
|
||||
var change_len_old = change_len;
|
||||
var change_len_new = new_str.length;
|
||||
|
||||
// Prepare new source string.
|
||||
var new_source = old_source.substring(0, change_pos) +
|
||||
new_str + old_source.substring(change_pos + change_len);
|
||||
|
||||
// Find all SharedFunctionInfo's that are compiled from this script.
|
||||
var shared_raw_list = %LiveEditFindSharedFunctionInfosForScript(script);
|
||||
|
||||
var shared_infos = new Array();
|
||||
|
||||
for (var i = 0; i < shared_raw_list.length; i++) {
|
||||
shared_infos.push(new liveedit.SharedInfoWrapper(shared_raw_list[i]));
|
||||
}
|
||||
|
||||
// Gather compile information about old version of script.
|
||||
var old_compile_info = DebugGatherCompileInfo(old_source);
|
||||
|
||||
// Gather compile information about new version of script.
|
||||
var new_compile_info;
|
||||
try {
|
||||
new_compile_info = DebugGatherCompileInfo(new_source);
|
||||
} catch (e) {
|
||||
throw new liveedit.Failure("Failed to compile new version of script: " + e);
|
||||
}
|
||||
|
||||
// An index of a single function, that is going to have its code replaced.
|
||||
var function_being_patched =
|
||||
FindChangedFunction(old_compile_info, change_pos, change_len_old);
|
||||
|
||||
// In old and new script versions function with a change should have the
|
||||
// same indexes.
|
||||
var function_being_patched2 =
|
||||
FindChangedFunction(new_compile_info, change_pos, change_len_new);
|
||||
Assert(function_being_patched == function_being_patched2,
|
||||
"inconsistent old/new compile info");
|
||||
|
||||
// Check that function being patched has the same expectations in a new
|
||||
// version. Otherwise we cannot safely patch its behavior and should
|
||||
// choose the outer function instead.
|
||||
while (!liveedit.CompareFunctionExpectations(
|
||||
old_compile_info[function_being_patched],
|
||||
new_compile_info[function_being_patched])) {
|
||||
|
||||
Assert(old_compile_info[function_being_patched].outer_index ==
|
||||
new_compile_info[function_being_patched].outer_index);
|
||||
function_being_patched =
|
||||
old_compile_info[function_being_patched].outer_index;
|
||||
Assert(function_being_patched != -1);
|
||||
}
|
||||
|
||||
// Check that function being patched is not currently on stack.
|
||||
liveedit.CheckStackActivations(
|
||||
[ FindFunctionInfo(function_being_patched) ], change_log );
|
||||
|
||||
|
||||
// Committing all changes.
|
||||
var old_script_name = liveedit.CreateNameForOldScript(script);
|
||||
|
||||
// Update the script text and create a new script representing an old
|
||||
// version of the script.
|
||||
var old_script = %LiveEditReplaceScript(script, new_source, old_script_name);
|
||||
|
||||
PatchCode(new_compile_info[function_being_patched],
|
||||
FindFunctionInfo(function_being_patched));
|
||||
|
||||
var position_patch_report = new Array();
|
||||
change_log.push( {position_patched: position_patch_report} );
|
||||
|
||||
var position_change_array = [ change_pos,
|
||||
change_pos + change_len_old,
|
||||
change_pos + change_len_new ];
|
||||
|
||||
// Update positions of all outer functions (i.e. all functions, that
|
||||
// are partially below the function being patched).
|
||||
for (var i = new_compile_info[function_being_patched].outer_index;
|
||||
i != -1;
|
||||
i = new_compile_info[i].outer_index) {
|
||||
PatchPositions(new_compile_info[i], FindFunctionInfo(i));
|
||||
}
|
||||
|
||||
// Update positions of all functions that are fully below the function
|
||||
// being patched.
|
||||
var old_next_sibling =
|
||||
old_compile_info[function_being_patched].next_sibling_index;
|
||||
var new_next_sibling =
|
||||
new_compile_info[function_being_patched].next_sibling_index;
|
||||
|
||||
// We simply go over the tail of both old and new lists. Their tails should
|
||||
// have an identical structure.
|
||||
if (old_next_sibling == -1) {
|
||||
Assert(new_next_sibling == -1);
|
||||
} else {
|
||||
Assert(old_compile_info.length - old_next_sibling ==
|
||||
new_compile_info.length - new_next_sibling);
|
||||
|
||||
for (var i = old_next_sibling, j = new_next_sibling;
|
||||
i < old_compile_info.length; i++, j++) {
|
||||
PatchPositions(new_compile_info[j], FindFunctionInfo(i));
|
||||
}
|
||||
}
|
||||
|
||||
var link_to_old_script_report = new Array();
|
||||
change_log.push( { linked_to_old_script: link_to_old_script_report } );
|
||||
|
||||
// We need to link to old script all former nested functions.
|
||||
for (var i = function_being_patched + 1; i < old_next_sibling; i++) {
|
||||
LinkToOldScript(FindFunctionInfo(i), old_script);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LiveEditChangeScript.Assert = function(condition, message) {
|
||||
if (!condition) {
|
||||
if (message) {
|
||||
throw "Assert " + message;
|
||||
} else {
|
||||
throw "Assert";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An object describing function compilation details. Its index fields
|
||||
// apply to indexes inside array that stores these objects.
|
||||
Debug.LiveEditChangeScript.FunctionCompileInfo = function(raw_array) {
|
||||
this.function_name = raw_array[0];
|
||||
this.start_position = raw_array[1];
|
||||
this.end_position = raw_array[2];
|
||||
this.param_num = raw_array[3];
|
||||
this.code = raw_array[4];
|
||||
this.scope_info = raw_array[5];
|
||||
this.outer_index = raw_array[6];
|
||||
this.next_sibling_index = null;
|
||||
this.raw_array = raw_array;
|
||||
}
|
||||
|
||||
// A structure describing SharedFunctionInfo.
|
||||
Debug.LiveEditChangeScript.SharedInfoWrapper = function(raw_array) {
|
||||
this.function_name = raw_array[0];
|
||||
this.start_position = raw_array[1];
|
||||
this.end_position = raw_array[2];
|
||||
this.info = raw_array[3];
|
||||
this.raw_array = raw_array;
|
||||
}
|
||||
|
||||
// Adds a suffix to script name to mark that it is old version.
|
||||
Debug.LiveEditChangeScript.CreateNameForOldScript = function(script) {
|
||||
// TODO(635): try better than this; support several changes.
|
||||
return script.name + " (old)";
|
||||
}
|
||||
|
||||
// Compares a function interface old and new version, whether it
|
||||
// changed or not.
|
||||
Debug.LiveEditChangeScript.CompareFunctionExpectations =
|
||||
function(function_info1, function_info2) {
|
||||
// Check that function has the same number of parameters (there may exist
|
||||
// an adapter, that won't survive function parameter number change).
|
||||
if (function_info1.param_num != function_info2.param_num) {
|
||||
return false;
|
||||
}
|
||||
var scope_info1 = function_info1.scope_info;
|
||||
var scope_info2 = function_info2.scope_info;
|
||||
|
||||
if (!scope_info1) {
|
||||
return !scope_info2;
|
||||
}
|
||||
|
||||
if (scope_info1.length != scope_info2.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that outer scope structure is not changed. Otherwise the function
|
||||
// will not properly work with existing scopes.
|
||||
return scope_info1.toString() == scope_info2.toString();
|
||||
}
|
||||
|
||||
// For array of wrapped shared function infos checks that none of them
|
||||
// have activations on stack (of any thread). Throws a Failure exception
|
||||
// if this proves to be false.
|
||||
Debug.LiveEditChangeScript.CheckStackActivations = function(shared_wrapper_list,
|
||||
change_log) {
|
||||
var liveedit = Debug.LiveEditChangeScript;
|
||||
|
||||
var shared_list = new Array();
|
||||
for (var i = 0; i < shared_wrapper_list.length; i++) {
|
||||
shared_list[i] = shared_wrapper_list[i].info;
|
||||
}
|
||||
var result = %LiveEditCheckStackActivations(shared_list);
|
||||
var problems = new Array();
|
||||
for (var i = 0; i < shared_list.length; i++) {
|
||||
if (result[i] == liveedit.FunctionPatchabilityStatus.FUNCTION_BLOCKED_ON_STACK) {
|
||||
var shared = shared_list[i];
|
||||
var description = {
|
||||
name: shared.function_name,
|
||||
start_pos: shared.start_position,
|
||||
end_pos: shared.end_position
|
||||
};
|
||||
problems.push(description);
|
||||
}
|
||||
}
|
||||
if (problems.length > 0) {
|
||||
change_log.push( { functions_on_stack: problems } );
|
||||
throw new liveedit.Failure("Blocked by functions on stack");
|
||||
}
|
||||
}
|
||||
|
||||
// A copy of the FunctionPatchabilityStatus enum from liveedit.h
|
||||
Debug.LiveEditChangeScript.FunctionPatchabilityStatus = {
|
||||
FUNCTION_AVAILABLE_FOR_PATCH: 0,
|
||||
FUNCTION_BLOCKED_ON_STACK: 1
|
||||
}
|
||||
|
||||
|
||||
// A logical failure in liveedit process. This means that change_log
|
||||
// is valid and consistent description of what happened.
|
||||
Debug.LiveEditChangeScript.Failure = function(message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
Debug.LiveEditChangeScript.Failure.prototype.toString = function() {
|
||||
return "LiveEdit Failure: " + this.message;
|
||||
}
|
||||
|
||||
// A testing entry.
|
||||
Debug.LiveEditChangeScript.GetPcFromSourcePos = function(func, source_pos) {
|
||||
return %GetFunctionCodePositionFromSource(func, source_pos);
|
||||
}
|
@ -91,7 +91,7 @@ class LiveEdit : AllStatic {
|
||||
static void PatchFunctionPositions(Handle<JSArray> shared_info_array,
|
||||
Handle<JSArray> position_change_array);
|
||||
|
||||
// A copy of this is in liveedit-delay.js.
|
||||
// A copy of this is in liveedit-debugger.js.
|
||||
enum FunctionPatchabilityStatus {
|
||||
FUNCTION_AVAILABLE_FOR_PATCH = 0,
|
||||
FUNCTION_BLOCKED_ON_STACK = 1
|
||||
|
@ -120,10 +120,6 @@ macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : NonStringToString
|
||||
# Macros implemented in Python.
|
||||
python macro CHAR_CODE(str) = ord(str[1]);
|
||||
|
||||
# Accessors for original global properties that ensure they have been loaded.
|
||||
const ORIGINAL_REGEXP = (global.RegExp, $RegExp);
|
||||
const ORIGINAL_DATE = (global.Date, $Date);
|
||||
|
||||
# Constants used on an array to implement the properties of the RegExp object.
|
||||
const REGEXP_NUMBER_OF_CAPTURES = 0;
|
||||
const REGEXP_FIRST_CAPTURE = 3;
|
||||
|
@ -27,6 +27,16 @@
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
//
|
||||
// Matches Script::Type from objects.h
|
||||
var TYPE_NATIVE = 0;
|
||||
var TYPE_EXTENSION = 1;
|
||||
var TYPE_NORMAL = 2;
|
||||
|
||||
// Matches Script::CompilationType from objects.h
|
||||
var COMPILATION_TYPE_HOST = 0;
|
||||
var COMPILATION_TYPE_EVAL = 1;
|
||||
var COMPILATION_TYPE_JSON = 2;
|
||||
|
||||
// Lazily initialized.
|
||||
var kVowelSounds = 0;
|
||||
@ -634,7 +644,7 @@ CallSite.prototype.isToplevel = function () {
|
||||
|
||||
CallSite.prototype.isEval = function () {
|
||||
var script = %FunctionGetScript(this.fun);
|
||||
return script && script.compilation_type == 1;
|
||||
return script && script.compilation_type == COMPILATION_TYPE_EVAL;
|
||||
};
|
||||
|
||||
CallSite.prototype.getEvalOrigin = function () {
|
||||
@ -656,7 +666,7 @@ CallSite.prototype.getFunctionName = function () {
|
||||
}
|
||||
// Maybe this is an evaluation?
|
||||
var script = %FunctionGetScript(this.fun);
|
||||
if (script && script.compilation_type == 1)
|
||||
if (script && script.compilation_type == COMPILATION_TYPE_EVAL)
|
||||
return "eval";
|
||||
return null;
|
||||
};
|
||||
@ -712,7 +722,7 @@ CallSite.prototype.getColumnNumber = function () {
|
||||
|
||||
CallSite.prototype.isNative = function () {
|
||||
var script = %FunctionGetScript(this.fun);
|
||||
return script ? (script.type == 0) : false;
|
||||
return script ? (script.type == TYPE_NATIVE) : false;
|
||||
};
|
||||
|
||||
CallSite.prototype.getPosition = function () {
|
||||
@ -736,7 +746,7 @@ function FormatEvalOrigin(script) {
|
||||
|
||||
var eval_from_script = script.eval_from_script;
|
||||
if (eval_from_script) {
|
||||
if (eval_from_script.compilation_type == 1) {
|
||||
if (eval_from_script.compilation_type == COMPILATION_TYPE_EVAL) {
|
||||
// eval script originated from another eval.
|
||||
eval_origin += " (eval at " + FormatEvalOrigin(eval_from_script) + ")";
|
||||
} else {
|
||||
|
@ -25,13 +25,6 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Touch the RegExp and Date functions to make sure that date-delay.js and
|
||||
// regexp-delay.js has been loaded. This is required as the mirrors use
|
||||
// functions within these files through the builtins object.
|
||||
RegExp;
|
||||
Date;
|
||||
|
||||
|
||||
// Handle id counters.
|
||||
var next_handle_ = 0;
|
||||
var next_transient_handle_ = -1;
|
@ -35,6 +35,7 @@
|
||||
#include "natives.h"
|
||||
#include "platform.h"
|
||||
#include "serialize.h"
|
||||
#include "list.h"
|
||||
|
||||
// use explicit namespace to avoid clashing with types in namespace v8
|
||||
namespace i = v8::internal;
|
||||
@ -96,7 +97,9 @@ static CounterMap counter_table_;
|
||||
|
||||
class CppByteSink : public i::SnapshotByteSink {
|
||||
public:
|
||||
explicit CppByteSink(const char* snapshot_file) : bytes_written_(0) {
|
||||
explicit CppByteSink(const char* snapshot_file)
|
||||
: bytes_written_(0),
|
||||
partial_sink_(this) {
|
||||
fp_ = i::OS::FOpen(snapshot_file, "wb");
|
||||
if (fp_ == NULL) {
|
||||
i::PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file);
|
||||
@ -111,11 +114,53 @@ class CppByteSink : public i::SnapshotByteSink {
|
||||
}
|
||||
|
||||
virtual ~CppByteSink() {
|
||||
if (fp_ != NULL) {
|
||||
fprintf(fp_, "};\n\n");
|
||||
fprintf(fp_, "int Snapshot::size_ = %d;\n\n", bytes_written_);
|
||||
fprintf(fp_, "} } // namespace v8::internal\n");
|
||||
fclose(fp_);
|
||||
fprintf(fp_, "const int Snapshot::size_ = %d;\n\n", bytes_written_);
|
||||
fprintf(fp_, "} } // namespace v8::internal\n");
|
||||
fclose(fp_);
|
||||
}
|
||||
|
||||
void WriteSpaceUsed(
|
||||
int new_space_used,
|
||||
int pointer_space_used,
|
||||
int data_space_used,
|
||||
int code_space_used,
|
||||
int map_space_used,
|
||||
int cell_space_used,
|
||||
int large_space_used) {
|
||||
fprintf(fp_, "};\n\n");
|
||||
fprintf(fp_, "const int Snapshot::new_space_used_ = %d;\n", new_space_used);
|
||||
fprintf(fp_,
|
||||
"const int Snapshot::pointer_space_used_ = %d;\n",
|
||||
pointer_space_used);
|
||||
fprintf(fp_,
|
||||
"const int Snapshot::data_space_used_ = %d;\n",
|
||||
data_space_used);
|
||||
fprintf(fp_,
|
||||
"const int Snapshot::code_space_used_ = %d;\n",
|
||||
code_space_used);
|
||||
fprintf(fp_, "const int Snapshot::map_space_used_ = %d;\n", map_space_used);
|
||||
fprintf(fp_,
|
||||
"const int Snapshot::cell_space_used_ = %d;\n",
|
||||
cell_space_used);
|
||||
fprintf(fp_,
|
||||
"const int Snapshot::large_space_used_ = %d;\n",
|
||||
large_space_used);
|
||||
}
|
||||
|
||||
void WritePartialSnapshot() {
|
||||
int length = partial_sink_.Position();
|
||||
fprintf(fp_, "};\n\n");
|
||||
fprintf(fp_, "const int Snapshot::context_size_ = %d;\n", length);
|
||||
fprintf(fp_, "const byte Snapshot::context_data_[] = {\n");
|
||||
for (int j = 0; j < length; j++) {
|
||||
if ((j & 0x1f) == 0x1f) {
|
||||
fprintf(fp_, "\n");
|
||||
}
|
||||
char byte = partial_sink_.at(j);
|
||||
if (j != 0) {
|
||||
fprintf(fp_, ",");
|
||||
}
|
||||
fprintf(fp_, "%d", byte);
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +170,7 @@ class CppByteSink : public i::SnapshotByteSink {
|
||||
}
|
||||
fprintf(fp_, "%d", byte);
|
||||
bytes_written_++;
|
||||
if ((bytes_written_ & 0x3f) == 0) {
|
||||
if ((bytes_written_ & 0x1f) == 0) {
|
||||
fprintf(fp_, "\n");
|
||||
}
|
||||
}
|
||||
@ -134,9 +179,28 @@ class CppByteSink : public i::SnapshotByteSink {
|
||||
return bytes_written_;
|
||||
}
|
||||
|
||||
i::SnapshotByteSink* partial_sink() { return &partial_sink_; }
|
||||
|
||||
class PartialSnapshotSink : public i::SnapshotByteSink {
|
||||
public:
|
||||
explicit PartialSnapshotSink(CppByteSink* parent)
|
||||
: parent_(parent),
|
||||
data_() { }
|
||||
virtual ~PartialSnapshotSink() { data_.Free(); }
|
||||
virtual void Put(int byte, const char* description) {
|
||||
data_.Add(byte);
|
||||
}
|
||||
virtual int Position() { return data_.length(); }
|
||||
char at(int i) { return data_[i]; }
|
||||
private:
|
||||
CppByteSink* parent_;
|
||||
i::List<char> data_;
|
||||
};
|
||||
|
||||
private:
|
||||
FILE* fp_;
|
||||
int bytes_written_;
|
||||
PartialSnapshotSink partial_sink_;
|
||||
};
|
||||
|
||||
|
||||
@ -162,12 +226,31 @@ int main(int argc, char** argv) {
|
||||
i::Bootstrapper::NativesSourceLookup(i);
|
||||
}
|
||||
}
|
||||
// If we don't do this then we end up with a stray root pointing at the
|
||||
// context even after we have disposed of the context.
|
||||
i::Heap::CollectAllGarbage(true);
|
||||
i::Object* raw_context = *(v8::Utils::OpenHandle(*context));
|
||||
context.Dispose();
|
||||
CppByteSink sink(argv[1]);
|
||||
// This results in a somewhat smaller snapshot, probably because it gets rid
|
||||
// of some things that are cached between garbage collections.
|
||||
i::Heap::CollectAllGarbage(true);
|
||||
i::StartupSerializer ser(&sink);
|
||||
ser.Serialize();
|
||||
ser.SerializeStrongReferences();
|
||||
|
||||
i::PartialSerializer partial_ser(&ser, sink.partial_sink());
|
||||
partial_ser.Serialize(&raw_context);
|
||||
|
||||
ser.SerializeWeakReferences();
|
||||
|
||||
sink.WritePartialSnapshot();
|
||||
|
||||
sink.WriteSpaceUsed(
|
||||
partial_ser.CurrentAllocationAddress(i::NEW_SPACE),
|
||||
partial_ser.CurrentAllocationAddress(i::OLD_POINTER_SPACE),
|
||||
partial_ser.CurrentAllocationAddress(i::OLD_DATA_SPACE),
|
||||
partial_ser.CurrentAllocationAddress(i::CODE_SPACE),
|
||||
partial_ser.CurrentAllocationAddress(i::MAP_SPACE),
|
||||
partial_ser.CurrentAllocationAddress(i::CELL_SPACE),
|
||||
partial_ser.CurrentAllocationAddress(i::LO_SPACE));
|
||||
return 0;
|
||||
}
|
||||
|
@ -44,13 +44,13 @@ class NativesCollection {
|
||||
public:
|
||||
// Number of built-in scripts.
|
||||
static int GetBuiltinsCount();
|
||||
// Number of delayed/lazy loading scripts.
|
||||
static int GetDelayCount();
|
||||
// Number of debugger implementation scripts.
|
||||
static int GetDebuggerCount();
|
||||
|
||||
// These are used to access built-in scripts.
|
||||
// The delayed script has an index in the interval [0, GetDelayCount()).
|
||||
// The non-delayed script has an index in the interval
|
||||
// [GetDelayCount(), GetNativesCount()).
|
||||
// These are used to access built-in scripts. The debugger implementation
|
||||
// scripts have an index in the interval [0, GetDebuggerCount()). The
|
||||
// non-debugger scripts have an index in the interval [GetDebuggerCount(),
|
||||
// GetNativesCount()).
|
||||
static int GetIndex(const char* name);
|
||||
static Vector<const char> GetScriptSource(int index);
|
||||
static Vector<const char> GetScriptName(int index);
|
||||
|
@ -615,9 +615,6 @@ void Map::MapPrint() {
|
||||
if (is_undetectable()) {
|
||||
PrintF(" - undetectable\n");
|
||||
}
|
||||
if (needs_loading()) {
|
||||
PrintF(" - needs_loading\n");
|
||||
}
|
||||
if (has_instance_call_handler()) {
|
||||
PrintF(" - instance_call_handler\n");
|
||||
}
|
||||
|
@ -2490,11 +2490,6 @@ bool JSFunction::IsBuiltin() {
|
||||
}
|
||||
|
||||
|
||||
bool JSObject::IsLoaded() {
|
||||
return !map()->needs_loading();
|
||||
}
|
||||
|
||||
|
||||
Code* JSFunction::code() {
|
||||
return shared()->code();
|
||||
}
|
||||
|
@ -338,55 +338,6 @@ PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
|
||||
}
|
||||
|
||||
|
||||
Object* JSObject::GetLazyProperty(Object* receiver,
|
||||
LookupResult* result,
|
||||
String* name,
|
||||
PropertyAttributes* attributes) {
|
||||
HandleScope scope;
|
||||
Handle<Object> this_handle(this);
|
||||
Handle<Object> receiver_handle(receiver);
|
||||
Handle<String> name_handle(name);
|
||||
bool pending_exception;
|
||||
LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())),
|
||||
&pending_exception);
|
||||
if (pending_exception) return Failure::Exception();
|
||||
return this_handle->GetPropertyWithReceiver(*receiver_handle,
|
||||
*name_handle,
|
||||
attributes);
|
||||
}
|
||||
|
||||
|
||||
Object* JSObject::SetLazyProperty(LookupResult* result,
|
||||
String* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes) {
|
||||
ASSERT(!IsJSGlobalProxy());
|
||||
HandleScope scope;
|
||||
Handle<JSObject> this_handle(this);
|
||||
Handle<String> name_handle(name);
|
||||
Handle<Object> value_handle(value);
|
||||
bool pending_exception;
|
||||
LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())),
|
||||
&pending_exception);
|
||||
if (pending_exception) return Failure::Exception();
|
||||
return this_handle->SetProperty(*name_handle, *value_handle, attributes);
|
||||
}
|
||||
|
||||
|
||||
Object* JSObject::DeleteLazyProperty(LookupResult* result,
|
||||
String* name,
|
||||
DeleteMode mode) {
|
||||
HandleScope scope;
|
||||
Handle<JSObject> this_handle(this);
|
||||
Handle<String> name_handle(name);
|
||||
bool pending_exception;
|
||||
LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())),
|
||||
&pending_exception);
|
||||
if (pending_exception) return Failure::Exception();
|
||||
return this_handle->DeleteProperty(*name_handle, mode);
|
||||
}
|
||||
|
||||
|
||||
Object* JSObject::GetNormalizedProperty(LookupResult* result) {
|
||||
ASSERT(!HasFastProperties());
|
||||
Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
|
||||
@ -530,12 +481,6 @@ Object* Object::GetProperty(Object* receiver,
|
||||
return Heap::undefined_value();
|
||||
}
|
||||
*attributes = result->GetAttributes();
|
||||
if (!result->IsLoaded()) {
|
||||
return JSObject::cast(this)->GetLazyProperty(receiver,
|
||||
result,
|
||||
name,
|
||||
attributes);
|
||||
}
|
||||
Object* value;
|
||||
JSObject* holder = result->holder();
|
||||
switch (result->type()) {
|
||||
@ -1786,7 +1731,6 @@ void JSObject::LocalLookupRealNamedProperty(String* name,
|
||||
return;
|
||||
}
|
||||
value = JSGlobalPropertyCell::cast(value)->value();
|
||||
ASSERT(result->IsLoaded());
|
||||
}
|
||||
// Make sure to disallow caching for uninitialized constants
|
||||
// found in the dictionary-mode objects.
|
||||
@ -1912,9 +1856,6 @@ Object* JSObject::SetProperty(LookupResult* result,
|
||||
// Neither properties nor transitions found.
|
||||
return AddProperty(name, value, attributes);
|
||||
}
|
||||
if (!result->IsLoaded()) {
|
||||
return SetLazyProperty(result, name, value, attributes);
|
||||
}
|
||||
if (result->IsReadOnly() && result->IsProperty()) return value;
|
||||
// This is a real property that is not read-only, or it is a
|
||||
// transition or null descriptor and there are no setters in the prototypes.
|
||||
@ -1994,9 +1935,7 @@ Object* JSObject::IgnoreAttributesAndSetLocalProperty(
|
||||
// Neither properties nor transitions found.
|
||||
return AddProperty(name, value, attributes);
|
||||
}
|
||||
if (!result.IsLoaded()) {
|
||||
return SetLazyProperty(&result, name, value, attributes);
|
||||
}
|
||||
|
||||
PropertyDetails details = PropertyDetails(attributes, NORMAL);
|
||||
|
||||
// Check of IsReadOnly removed from here in clone.
|
||||
@ -2514,11 +2453,6 @@ Object* JSObject::DeleteProperty(String* name, DeleteMode mode) {
|
||||
}
|
||||
return DeletePropertyWithInterceptor(name);
|
||||
}
|
||||
if (!result.IsLoaded()) {
|
||||
return JSObject::cast(this)->DeleteLazyProperty(&result,
|
||||
name,
|
||||
mode);
|
||||
}
|
||||
// Normalize object if needed.
|
||||
Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
|
||||
if (obj->IsFailure()) return obj;
|
||||
|
@ -1224,12 +1224,6 @@ class JSObject: public HeapObject {
|
||||
// Deletes the named property in a normalized object.
|
||||
Object* DeleteNormalizedProperty(String* name, DeleteMode mode);
|
||||
|
||||
// Sets a property that currently has lazy loading.
|
||||
Object* SetLazyProperty(LookupResult* result,
|
||||
String* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
// Returns the class name ([[Class]] property in the specification).
|
||||
String* class_name();
|
||||
|
||||
@ -1264,13 +1258,6 @@ class JSObject: public HeapObject {
|
||||
Object* GetLocalPropertyPostInterceptor(JSObject* receiver,
|
||||
String* name,
|
||||
PropertyAttributes* attributes);
|
||||
Object* GetLazyProperty(Object* receiver,
|
||||
LookupResult* result,
|
||||
String* name,
|
||||
PropertyAttributes* attributes);
|
||||
|
||||
// Tells whether this object needs to be loaded.
|
||||
inline bool IsLoaded();
|
||||
|
||||
// Returns true if this is an instance of an api function and has
|
||||
// been modified since it was created. May give false positives.
|
||||
@ -1308,9 +1295,6 @@ class JSObject: public HeapObject {
|
||||
|
||||
Object* DeleteProperty(String* name, DeleteMode mode);
|
||||
Object* DeleteElement(uint32_t index, DeleteMode mode);
|
||||
Object* DeleteLazyProperty(LookupResult* result,
|
||||
String* name,
|
||||
DeleteMode mode);
|
||||
|
||||
// Tests for the fast common case for property enumeration.
|
||||
bool IsSimpleEnum();
|
||||
@ -2892,20 +2876,6 @@ class Map: public HeapObject {
|
||||
return ((1 << kIsUndetectable) & bit_field()) != 0;
|
||||
}
|
||||
|
||||
inline void set_needs_loading(bool value) {
|
||||
if (value) {
|
||||
set_bit_field2(bit_field2() | (1 << kNeedsLoading));
|
||||
} else {
|
||||
set_bit_field2(bit_field2() & ~(1 << kNeedsLoading));
|
||||
}
|
||||
}
|
||||
|
||||
// Does this object or function require a lazily loaded script to be
|
||||
// run before being used?
|
||||
inline bool needs_loading() {
|
||||
return ((1 << kNeedsLoading) & bit_field2()) != 0;
|
||||
}
|
||||
|
||||
// Tells whether the instance has a call-as-function handler.
|
||||
inline void set_has_instance_call_handler() {
|
||||
set_bit_field(bit_field() | (1 << kHasInstanceCallHandler));
|
||||
@ -3039,8 +3009,7 @@ class Map: public HeapObject {
|
||||
static const int kIsAccessCheckNeeded = 7;
|
||||
|
||||
// Bit positions for bit field 2
|
||||
static const int kNeedsLoading = 0;
|
||||
static const int kIsExtensible = 1;
|
||||
static const int kIsExtensible = 0;
|
||||
|
||||
// Layout of the default cache. It holds alternating name and code objects.
|
||||
static const int kCodeCacheEntrySize = 2;
|
||||
|
@ -192,7 +192,8 @@ void OS::Abort() {
|
||||
|
||||
|
||||
void OS::DebugBreak() {
|
||||
#if defined(__arm__) || defined(__thumb__)
|
||||
#if (defined(__arm__) || defined(__thumb__)) && \
|
||||
defined(CAN_USE_ARMV5_INSTRUCTIONS)
|
||||
asm("bkpt 0");
|
||||
#else
|
||||
asm("int $3");
|
||||
|
@ -266,7 +266,8 @@ void OS::Abort() {
|
||||
void OS::DebugBreak() {
|
||||
// TODO(lrn): Introduce processor define for runtime system (!= V8_ARCH_x,
|
||||
// which is the architecture of generated code).
|
||||
#if defined(__arm__) || defined(__thumb__)
|
||||
#if (defined(__arm__) || defined(__thumb__)) && \
|
||||
defined(CAN_USE_ARMV5_INSTRUCTIONS)
|
||||
asm("bkpt 0");
|
||||
#elif defined(__mips__)
|
||||
asm("break");
|
||||
|
@ -190,7 +190,8 @@ void OS::Abort() {
|
||||
|
||||
|
||||
void OS::DebugBreak() {
|
||||
#if defined(__arm__) || defined(__thumb__)
|
||||
#if (defined(__arm__) || defined(__thumb__)) && \
|
||||
defined(CAN_USE_ARMV5_INSTRUCTIONS)
|
||||
asm("bkpt 0");
|
||||
#else
|
||||
asm("int $3");
|
||||
|
@ -511,7 +511,7 @@ void Time::SetToCurrentTime() {
|
||||
// takes into account whether daylight saving is in effect at the time.
|
||||
// Only times in the 32-bit Unix range may be passed to this function.
|
||||
// Also, adding the time-zone offset to the input must not overflow.
|
||||
// The function EquivalentTime() in date-delay.js guarantees this.
|
||||
// The function EquivalentTime() in date.js guarantees this.
|
||||
int64_t Time::LocalOffset() {
|
||||
// Initialize timezone information, if needed.
|
||||
TzSet();
|
||||
|
@ -239,15 +239,6 @@ class LookupResult BASE_EMBEDDED {
|
||||
bool IsCacheable() { return cacheable_; }
|
||||
void DisallowCaching() { cacheable_ = false; }
|
||||
|
||||
// Tells whether the value needs to be loaded.
|
||||
bool IsLoaded() {
|
||||
if (lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE) {
|
||||
Object* target = GetLazyValue();
|
||||
return !target->IsJSObject() || JSObject::cast(target)->IsLoaded();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Object* GetLazyValue() {
|
||||
switch (type()) {
|
||||
case FIELD:
|
||||
|
@ -3100,7 +3100,7 @@ static Object* Runtime_KeyedGetProperty(Arguments args) {
|
||||
// Lookup cache miss. Perform lookup and update the cache if appropriate.
|
||||
LookupResult result;
|
||||
receiver->LocalLookup(key, &result);
|
||||
if (result.IsProperty() && result.IsLoaded() && result.type() == FIELD) {
|
||||
if (result.IsProperty() && result.type() == FIELD) {
|
||||
int offset = result.GetFieldIndex();
|
||||
KeyedLookupCache::Update(receiver_map, key, offset);
|
||||
return receiver->FastPropertyAt(offset);
|
||||
|
@ -547,7 +547,7 @@ Address Deserializer::Allocate(int space_index, Space* space, int size) {
|
||||
HeapObject* new_object = HeapObject::cast(new_allocation);
|
||||
// Record all large objects in the same space.
|
||||
address = new_object->address();
|
||||
high_water_[LO_SPACE] = address + size;
|
||||
pages_[LO_SPACE].Add(address);
|
||||
}
|
||||
last_object_address_ = address;
|
||||
return address;
|
||||
@ -900,7 +900,7 @@ void Serializer::Synchronize(const char* tag) {
|
||||
Serializer::Serializer(SnapshotByteSink* sink)
|
||||
: sink_(sink),
|
||||
current_root_index_(0),
|
||||
external_reference_encoder_(NULL),
|
||||
external_reference_encoder_(new ExternalReferenceEncoder),
|
||||
large_object_total_(0) {
|
||||
for (int i = 0; i <= LAST_SPACE; i++) {
|
||||
fullness_[i] = 0;
|
||||
@ -908,28 +908,28 @@ Serializer::Serializer(SnapshotByteSink* sink)
|
||||
}
|
||||
|
||||
|
||||
Serializer::~Serializer() {
|
||||
delete external_reference_encoder_;
|
||||
}
|
||||
|
||||
|
||||
void StartupSerializer::SerializeStrongReferences() {
|
||||
// No active threads.
|
||||
CHECK_EQ(NULL, ThreadState::FirstInUse());
|
||||
// No active or weak handles.
|
||||
CHECK(HandleScopeImplementer::instance()->blocks()->is_empty());
|
||||
CHECK_EQ(0, GlobalHandles::NumberOfWeakHandles());
|
||||
CHECK_EQ(NULL, external_reference_encoder_);
|
||||
// We don't support serializing installed extensions.
|
||||
for (RegisteredExtension* ext = RegisteredExtension::first_extension();
|
||||
ext != NULL;
|
||||
ext = ext->next()) {
|
||||
CHECK_NE(v8::INSTALLED, ext->state());
|
||||
}
|
||||
external_reference_encoder_ = new ExternalReferenceEncoder();
|
||||
Heap::IterateStrongRoots(this, VISIT_ONLY_STRONG);
|
||||
delete external_reference_encoder_;
|
||||
external_reference_encoder_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
void PartialSerializer::Serialize(Object** object) {
|
||||
external_reference_encoder_ = new ExternalReferenceEncoder();
|
||||
this->VisitPointer(object);
|
||||
|
||||
// After we have done the partial serialization the partial snapshot cache
|
||||
@ -943,9 +943,6 @@ void PartialSerializer::Serialize(Object** object) {
|
||||
startup_serializer_->VisitPointer(&partial_snapshot_cache_[index]);
|
||||
}
|
||||
partial_snapshot_cache_length_ = kPartialSnapshotCacheCapacity;
|
||||
|
||||
delete external_reference_encoder_;
|
||||
external_reference_encoder_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -997,6 +994,7 @@ int PartialSerializer::PartialSnapshotCacheIndex(HeapObject* heap_object) {
|
||||
Object* entry = partial_snapshot_cache_[i];
|
||||
if (entry == heap_object) return i;
|
||||
}
|
||||
|
||||
// We didn't find the object in the cache. So we add it to the cache and
|
||||
// then visit the pointer so that it becomes part of the startup snapshot
|
||||
// and we can refer to it from the partial snapshot.
|
||||
|
@ -120,28 +120,9 @@ class SnapshotByteSource {
|
||||
return data_[position_++];
|
||||
}
|
||||
|
||||
void CopyRaw(byte* to, int number_of_bytes) {
|
||||
memcpy(to, data_ + position_, number_of_bytes);
|
||||
position_ += number_of_bytes;
|
||||
}
|
||||
inline void CopyRaw(byte* to, int number_of_bytes);
|
||||
|
||||
int GetInt() {
|
||||
// A little unwind to catch the really small ints.
|
||||
int snapshot_byte = Get();
|
||||
if ((snapshot_byte & 0x80) == 0) {
|
||||
return snapshot_byte;
|
||||
}
|
||||
int accumulator = (snapshot_byte & 0x7f) << 7;
|
||||
while (true) {
|
||||
snapshot_byte = Get();
|
||||
if ((snapshot_byte & 0x80) == 0) {
|
||||
return accumulator | snapshot_byte;
|
||||
}
|
||||
accumulator = (accumulator | (snapshot_byte & 0x7f)) << 7;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return accumulator;
|
||||
}
|
||||
inline int GetInt();
|
||||
|
||||
bool AtEOF() {
|
||||
return position_ == length_;
|
||||
@ -235,11 +216,35 @@ class SerializerDeserializer: public ObjectVisitor {
|
||||
}
|
||||
|
||||
static int partial_snapshot_cache_length_;
|
||||
static const int kPartialSnapshotCacheCapacity = 1024;
|
||||
static const int kPartialSnapshotCacheCapacity = 1300;
|
||||
static Object* partial_snapshot_cache_[];
|
||||
};
|
||||
|
||||
|
||||
int SnapshotByteSource::GetInt() {
|
||||
// A little unwind to catch the really small ints.
|
||||
int snapshot_byte = Get();
|
||||
if ((snapshot_byte & 0x80) == 0) {
|
||||
return snapshot_byte;
|
||||
}
|
||||
int accumulator = (snapshot_byte & 0x7f) << 7;
|
||||
while (true) {
|
||||
snapshot_byte = Get();
|
||||
if ((snapshot_byte & 0x80) == 0) {
|
||||
return accumulator | snapshot_byte;
|
||||
}
|
||||
accumulator = (accumulator | (snapshot_byte & 0x7f)) << 7;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
|
||||
void SnapshotByteSource::CopyRaw(byte* to, int number_of_bytes) {
|
||||
memcpy(to, data_ + position_, number_of_bytes);
|
||||
position_ += number_of_bytes;
|
||||
}
|
||||
|
||||
|
||||
// A Deserializer reads a snapshot and reconstructs the Object graph it defines.
|
||||
class Deserializer: public SerializerDeserializer {
|
||||
@ -364,6 +369,7 @@ class SerializationAddressMapper {
|
||||
class Serializer : public SerializerDeserializer {
|
||||
public:
|
||||
explicit Serializer(SnapshotByteSink* sink);
|
||||
~Serializer();
|
||||
void VisitPointers(Object** start, Object** end);
|
||||
// You can call this after serialization to find out how much space was used
|
||||
// in each space.
|
||||
@ -492,7 +498,12 @@ class PartialSerializer : public Serializer {
|
||||
virtual int RootIndex(HeapObject* o);
|
||||
virtual int PartialSnapshotCacheIndex(HeapObject* o);
|
||||
virtual bool ShouldBeInThePartialSnapshotCache(HeapObject* o) {
|
||||
return o->IsString() || o->IsSharedFunctionInfo();
|
||||
// Scripts should be referred only through shared function infos. We can't
|
||||
// allow them to be part of the partial snapshot because they contain a
|
||||
// unique ID, and deserializing several partial snapshots containing script
|
||||
// would cause dupes.
|
||||
ASSERT(!o->IsScript());
|
||||
return o->IsString() || o->IsSharedFunctionInfo() || o->IsHeapNumber();
|
||||
}
|
||||
|
||||
private:
|
||||
@ -530,6 +541,7 @@ class StartupSerializer : public Serializer {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
||||
#endif // V8_SERIALIZE_H_
|
||||
|
@ -59,4 +59,24 @@ bool Snapshot::Initialize(const char* snapshot_file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Handle<Context> Snapshot::NewContextFromSnapshot() {
|
||||
if (context_size_ == 0) {
|
||||
return Handle<Context>();
|
||||
}
|
||||
Heap::ReserveSpace(new_space_used_,
|
||||
pointer_space_used_,
|
||||
data_space_used_,
|
||||
code_space_used_,
|
||||
map_space_used_,
|
||||
cell_space_used_,
|
||||
large_space_used_);
|
||||
SnapshotByteSource source(context_data_, context_size_);
|
||||
Deserializer deserializer(&source);
|
||||
Object* root;
|
||||
deserializer.DeserializePartial(&root);
|
||||
CHECK(root->IsContext());
|
||||
return Handle<Context>(Context::cast(root));
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -35,6 +35,16 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
const byte Snapshot::data_[] = { 0 };
|
||||
int Snapshot::size_ = 0;
|
||||
const int Snapshot::size_ = 0;
|
||||
const byte Snapshot::context_data_[] = { 0 };
|
||||
const int Snapshot::context_size_ = 0;
|
||||
|
||||
const int Snapshot::new_space_used_ = 0;
|
||||
const int Snapshot::pointer_space_used_ = 0;
|
||||
const int Snapshot::data_space_used_ = 0;
|
||||
const int Snapshot::code_space_used_ = 0;
|
||||
const int Snapshot::map_space_used_ = 0;
|
||||
const int Snapshot::cell_space_used_ = 0;
|
||||
const int Snapshot::large_space_used_ = 0;
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -38,6 +38,9 @@ class Snapshot {
|
||||
// could be found.
|
||||
static bool Initialize(const char* snapshot_file = NULL);
|
||||
|
||||
// Create a new context using the internal partial snapshot.
|
||||
static Handle<Context> NewContextFromSnapshot();
|
||||
|
||||
// Returns whether or not the snapshot is enabled.
|
||||
static bool IsEnabled() { return size_ != 0; }
|
||||
|
||||
@ -47,7 +50,16 @@ class Snapshot {
|
||||
|
||||
private:
|
||||
static const byte data_[];
|
||||
static int size_;
|
||||
static const byte context_data_[];
|
||||
static const int new_space_used_;
|
||||
static const int pointer_space_used_;
|
||||
static const int data_space_used_;
|
||||
static const int code_space_used_;
|
||||
static const int map_space_used_;
|
||||
static const int cell_space_used_;
|
||||
static const int large_space_used_;
|
||||
static const int size_;
|
||||
static const int context_size_;
|
||||
|
||||
static bool Deserialize(const byte* content, int len);
|
||||
|
||||
|
@ -164,7 +164,7 @@ function StringLocaleCompare(other) {
|
||||
|
||||
// ECMA-262 section 15.5.4.10
|
||||
function StringMatch(regexp) {
|
||||
if (!IS_REGEXP(regexp)) regexp = new ORIGINAL_REGEXP(regexp);
|
||||
if (!IS_REGEXP(regexp)) regexp = new $RegExp(regexp);
|
||||
var subject = TO_STRING_INLINE(this);
|
||||
|
||||
if (!regexp.global) return regexp.exec(subject);
|
||||
@ -183,7 +183,7 @@ function StringMatch(regexp) {
|
||||
}
|
||||
|
||||
%_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
|
||||
// lastMatchInfo is defined in regexp-delay.js.
|
||||
// lastMatchInfo is defined in regexp.js.
|
||||
var result = %StringMatch(subject, regexp, lastMatchInfo);
|
||||
cache.type = 'match';
|
||||
cache.regExp = regexp;
|
||||
@ -523,7 +523,7 @@ function ApplyReplacementFunction(replace, matchInfo, subject) {
|
||||
|
||||
// ECMA-262 section 15.5.4.12
|
||||
function StringSearch(re) {
|
||||
var regexp = new ORIGINAL_REGEXP(re);
|
||||
var regexp = new $RegExp(re);
|
||||
var s = TO_STRING_INLINE(this);
|
||||
var last_idx = regexp.lastIndex; // keep old lastIndex
|
||||
regexp.lastIndex = 0; // ignore re.global property
|
||||
@ -896,6 +896,7 @@ function StringSup() {
|
||||
|
||||
// ReplaceResultBuilder support.
|
||||
function ReplaceResultBuilder(str) {
|
||||
this.__proto__ = void 0;
|
||||
this.elements = new $Array();
|
||||
this.special_string = str;
|
||||
}
|
||||
|
@ -679,7 +679,7 @@ void Top::PrintCurrentStackTrace(FILE* out) {
|
||||
|
||||
|
||||
void Top::ComputeLocation(MessageLocation* target) {
|
||||
*target = MessageLocation(empty_script(), -1, -1);
|
||||
*target = MessageLocation(Handle<Script>(Heap::empty_script()), -1, -1);
|
||||
StackTraceFrameIterator it;
|
||||
if (!it.done()) {
|
||||
JavaScriptFrame* frame = it.frame();
|
||||
|
@ -97,7 +97,11 @@ namespace internal {
|
||||
/* Amount of source code compiled with the old codegen. */ \
|
||||
SC(total_old_codegen_source_size, V8.TotalOldCodegenSourceSize) \
|
||||
/* Amount of source code compiled with the full codegen. */ \
|
||||
SC(total_full_codegen_source_size, V8.TotalFullCodegenSourceSize)
|
||||
SC(total_full_codegen_source_size, V8.TotalFullCodegenSourceSize) \
|
||||
/* Number of contexts created from scratch. */ \
|
||||
SC(contexts_created_from_scratch, V8.ContextsCreatedFromScratch) \
|
||||
/* Number of contexts created by partial snapshot. */ \
|
||||
SC(contexts_created_by_snapshot, V8.ContextsCreatedBySnapshot)
|
||||
|
||||
|
||||
#define STATS_COUNTER_LIST_2(SC) \
|
||||
@ -187,6 +191,7 @@ namespace internal {
|
||||
SC(transcendental_cache_hit, V8.TranscendentalCacheHit) \
|
||||
SC(transcendental_cache_miss, V8.TranscendentalCacheMiss)
|
||||
|
||||
|
||||
// This file contains all the v8 counters that are in use.
|
||||
class Counters : AllStatic {
|
||||
public:
|
||||
|
@ -253,22 +253,6 @@ static void GenerateNumberDictionaryLoad(MacroAssembler* masm,
|
||||
}
|
||||
|
||||
|
||||
// Helper function used to check that a value is either not an object
|
||||
// or is loaded if it is an object.
|
||||
static void GenerateCheckNonObjectOrLoaded(MacroAssembler* masm, Label* miss,
|
||||
Register value) {
|
||||
Label done;
|
||||
// Check if the value is a Smi.
|
||||
__ JumpIfSmi(value, &done);
|
||||
// Check if the object has been loaded.
|
||||
__ movq(kScratchRegister, FieldOperand(value, JSFunction::kMapOffset));
|
||||
__ testb(FieldOperand(kScratchRegister, Map::kBitField2Offset),
|
||||
Immediate(1 << Map::kNeedsLoading));
|
||||
__ j(not_zero, miss);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
// One byte opcode for test eax,0xXXXXXXXX.
|
||||
static const byte kTestEaxByte = 0xA9;
|
||||
|
||||
@ -522,7 +506,6 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
||||
rdx,
|
||||
rax,
|
||||
DICTIONARY_CHECK_DONE);
|
||||
GenerateCheckNonObjectOrLoaded(masm, &slow, rcx);
|
||||
__ movq(rax, rcx);
|
||||
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
|
||||
__ ret(0);
|
||||
@ -1231,10 +1214,6 @@ static void GenerateNormalHelper(MacroAssembler* masm,
|
||||
// Check that the value is a JavaScript function.
|
||||
__ CmpObjectType(rdx, JS_FUNCTION_TYPE, rdx);
|
||||
__ j(not_equal, miss);
|
||||
// Check that the function has been loaded.
|
||||
__ testb(FieldOperand(rdx, Map::kBitField2Offset),
|
||||
Immediate(1 << Map::kNeedsLoading));
|
||||
__ j(not_zero, miss);
|
||||
|
||||
// Patch the receiver with the global proxy if necessary.
|
||||
if (is_global_object) {
|
||||
@ -1431,7 +1410,6 @@ void LoadIC::GenerateNormal(MacroAssembler* masm) {
|
||||
// Search the dictionary placing the result in rax.
|
||||
__ bind(&probe);
|
||||
GenerateDictionaryLoad(masm, &miss, rdx, rax, rbx, rcx, CHECK_DICTIONARY);
|
||||
GenerateCheckNonObjectOrLoaded(masm, &miss, rax);
|
||||
__ ret(0);
|
||||
|
||||
// Global object access: Check access rights.
|
||||
|
@ -783,7 +783,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
|
||||
// -----------------------------------
|
||||
|
||||
SharedFunctionInfo* function_info = function->shared();
|
||||
if (function_info->HasCustomCallGenerator()) {
|
||||
if (false && function_info->HasCustomCallGenerator()) {
|
||||
CustomCallGenerator generator =
|
||||
ToCData<CustomCallGenerator>(function_info->function_data());
|
||||
return generator(this, object, holder, function, name, check);
|
||||
|
@ -40,7 +40,6 @@ test-api/ApplyInterruption: PASS || TIMEOUT
|
||||
test-serialize/TestThatAlwaysFails: FAIL
|
||||
test-serialize/DependentTestThatAlwaysFails: FAIL
|
||||
|
||||
|
||||
[ $arch == arm ]
|
||||
|
||||
# BUG(240): Test seems flaky on ARM.
|
||||
|
@ -38,7 +38,7 @@
|
||||
#include "utils.h"
|
||||
#include "cctest.h"
|
||||
|
||||
static const bool kLogThreading = false;
|
||||
static const bool kLogThreading = true;
|
||||
|
||||
static bool IsNaN(double x) {
|
||||
#ifdef WIN32
|
||||
@ -4605,6 +4605,7 @@ THREADED_TEST(AccessControl) {
|
||||
value = v8_compile("other.accessible_prop = 3")->Run();
|
||||
CHECK(value->IsNumber());
|
||||
CHECK_EQ(3, value->Int32Value());
|
||||
CHECK_EQ(3, g_echo_value);
|
||||
|
||||
value = v8_compile("other.accessible_prop")->Run();
|
||||
CHECK(value->IsNumber());
|
||||
|
@ -47,9 +47,6 @@ static v8::Persistent<v8::Context> env;
|
||||
|
||||
// The test framework does not accept flags on the command line, so we set them
|
||||
static void InitializeVM() {
|
||||
// disable compilation of natives by specifying an empty natives file
|
||||
FLAG_natives_file = "";
|
||||
|
||||
// enable generation of comments
|
||||
FLAG_debug_code = true;
|
||||
|
||||
|
@ -289,65 +289,68 @@ static void SanityCheck() {
|
||||
|
||||
|
||||
DEPENDENT_TEST(Deserialize, Serialize) {
|
||||
v8::HandleScope scope;
|
||||
// The serialize-deserialize tests only work if the VM is built without
|
||||
// serialization. That doesn't matter. We don't need to be able to
|
||||
// serialize a snapshot in a VM that is booted from a snapshot.
|
||||
if (!Snapshot::IsEnabled()) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
Deserialize();
|
||||
Deserialize();
|
||||
|
||||
v8::Persistent<v8::Context> env = v8::Context::New();
|
||||
env->Enter();
|
||||
v8::Persistent<v8::Context> env = v8::Context::New();
|
||||
env->Enter();
|
||||
|
||||
SanityCheck();
|
||||
SanityCheck();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DEPENDENT_TEST(DeserializeFromSecondSerialization, SerializeTwice) {
|
||||
// BUG(632): Disable this test until the partial_snapshots branch is
|
||||
// merged back.
|
||||
return;
|
||||
if (!Snapshot::IsEnabled()) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
v8::HandleScope scope;
|
||||
Deserialize();
|
||||
|
||||
Deserialize();
|
||||
v8::Persistent<v8::Context> env = v8::Context::New();
|
||||
env->Enter();
|
||||
|
||||
v8::Persistent<v8::Context> env = v8::Context::New();
|
||||
env->Enter();
|
||||
|
||||
SanityCheck();
|
||||
SanityCheck();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DEPENDENT_TEST(DeserializeAndRunScript2, Serialize) {
|
||||
v8::HandleScope scope;
|
||||
if (!Snapshot::IsEnabled()) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
Deserialize();
|
||||
Deserialize();
|
||||
|
||||
v8::Persistent<v8::Context> env = v8::Context::New();
|
||||
env->Enter();
|
||||
v8::Persistent<v8::Context> env = v8::Context::New();
|
||||
env->Enter();
|
||||
|
||||
const char* c_source = "\"1234\".length";
|
||||
v8::Local<v8::String> source = v8::String::New(c_source);
|
||||
v8::Local<v8::Script> script = v8::Script::Compile(source);
|
||||
CHECK_EQ(4, script->Run()->Int32Value());
|
||||
const char* c_source = "\"1234\".length";
|
||||
v8::Local<v8::String> source = v8::String::New(c_source);
|
||||
v8::Local<v8::Script> script = v8::Script::Compile(source);
|
||||
CHECK_EQ(4, script->Run()->Int32Value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DEPENDENT_TEST(DeserializeFromSecondSerializationAndRunScript2,
|
||||
SerializeTwice) {
|
||||
// BUG(632): Disable this test until the partial_snapshots branch is
|
||||
// merged back.
|
||||
return;
|
||||
if (!Snapshot::IsEnabled()) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
v8::HandleScope scope;
|
||||
Deserialize();
|
||||
|
||||
Deserialize();
|
||||
v8::Persistent<v8::Context> env = v8::Context::New();
|
||||
env->Enter();
|
||||
|
||||
v8::Persistent<v8::Context> env = v8::Context::New();
|
||||
env->Enter();
|
||||
|
||||
const char* c_source = "\"1234\".length";
|
||||
v8::Local<v8::String> source = v8::String::New(c_source);
|
||||
v8::Local<v8::Script> script = v8::Script::Compile(source);
|
||||
CHECK_EQ(4, script->Run()->Int32Value());
|
||||
const char* c_source = "\"1234\".length";
|
||||
v8::Local<v8::String> source = v8::String::New(c_source);
|
||||
v8::Local<v8::Script> script = v8::Script::Compile(source);
|
||||
CHECK_EQ(4, script->Run()->Int32Value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -400,14 +403,8 @@ TEST(PartialSerialization) {
|
||||
}
|
||||
|
||||
|
||||
DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
|
||||
int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
|
||||
Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
|
||||
OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
|
||||
|
||||
CHECK(Snapshot::Initialize(startup_name.start()));
|
||||
|
||||
const char* file_name = FLAG_testing_serialization_file;
|
||||
static void ReserveSpaceForPartialSnapshot(const char* file_name) {
|
||||
int file_name_length = StrLength(file_name) + 10;
|
||||
Vector<char> name = Vector<char>::New(file_name_length + 1);
|
||||
OS::SNPrintF(name, "%s.size", file_name);
|
||||
FILE* fp = OS::FOpen(name.start(), "r");
|
||||
@ -436,26 +433,122 @@ DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
|
||||
map_size,
|
||||
cell_size,
|
||||
large_size);
|
||||
int snapshot_size = 0;
|
||||
byte* snapshot = ReadBytes(file_name, &snapshot_size);
|
||||
}
|
||||
|
||||
Object* root;
|
||||
{
|
||||
SnapshotByteSource source(snapshot, snapshot_size);
|
||||
Deserializer deserializer(&source);
|
||||
deserializer.DeserializePartial(&root);
|
||||
CHECK(root->IsString());
|
||||
|
||||
DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
|
||||
if (!Snapshot::IsEnabled()) {
|
||||
int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
|
||||
Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
|
||||
OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
|
||||
|
||||
CHECK(Snapshot::Initialize(startup_name.start()));
|
||||
|
||||
const char* file_name = FLAG_testing_serialization_file;
|
||||
ReserveSpaceForPartialSnapshot(file_name);
|
||||
|
||||
int snapshot_size = 0;
|
||||
byte* snapshot = ReadBytes(file_name, &snapshot_size);
|
||||
|
||||
Object* root;
|
||||
{
|
||||
SnapshotByteSource source(snapshot, snapshot_size);
|
||||
Deserializer deserializer(&source);
|
||||
deserializer.DeserializePartial(&root);
|
||||
CHECK(root->IsString());
|
||||
}
|
||||
v8::HandleScope handle_scope;
|
||||
Handle<Object>root_handle(root);
|
||||
|
||||
Object* root2;
|
||||
{
|
||||
SnapshotByteSource source(snapshot, snapshot_size);
|
||||
Deserializer deserializer(&source);
|
||||
deserializer.DeserializePartial(&root2);
|
||||
CHECK(root2->IsString());
|
||||
CHECK(*root_handle == root2);
|
||||
}
|
||||
}
|
||||
v8::HandleScope handle_scope;
|
||||
Handle<Object>root_handle(root);
|
||||
}
|
||||
|
||||
Object* root2;
|
||||
{
|
||||
SnapshotByteSource source(snapshot, snapshot_size);
|
||||
Deserializer deserializer(&source);
|
||||
deserializer.DeserializePartial(&root2);
|
||||
CHECK(root2->IsString());
|
||||
CHECK(*root_handle == root2);
|
||||
|
||||
TEST(ContextSerialization) {
|
||||
Serializer::Enable();
|
||||
v8::V8::Initialize();
|
||||
|
||||
v8::Persistent<v8::Context> env = v8::Context::New();
|
||||
ASSERT(!env.IsEmpty());
|
||||
env->Enter();
|
||||
// Make sure all builtin scripts are cached.
|
||||
{ HandleScope scope;
|
||||
for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
|
||||
Bootstrapper::NativesSourceLookup(i);
|
||||
}
|
||||
}
|
||||
// If we don't do this then we end up with a stray root pointing at the
|
||||
// context even after we have disposed of env.
|
||||
Heap::CollectAllGarbage(true);
|
||||
|
||||
int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
|
||||
Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
|
||||
OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
|
||||
|
||||
env->Exit();
|
||||
|
||||
Object* raw_context = *(v8::Utils::OpenHandle(*env));
|
||||
|
||||
env.Dispose();
|
||||
|
||||
FileByteSink startup_sink(startup_name.start());
|
||||
StartupSerializer startup_serializer(&startup_sink);
|
||||
startup_serializer.SerializeStrongReferences();
|
||||
|
||||
FileByteSink partial_sink(FLAG_testing_serialization_file);
|
||||
PartialSerializer p_ser(&startup_serializer, &partial_sink);
|
||||
p_ser.Serialize(&raw_context);
|
||||
startup_serializer.SerializeWeakReferences();
|
||||
partial_sink.WriteSpaceUsed(p_ser.CurrentAllocationAddress(NEW_SPACE),
|
||||
p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
|
||||
p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
|
||||
p_ser.CurrentAllocationAddress(CODE_SPACE),
|
||||
p_ser.CurrentAllocationAddress(MAP_SPACE),
|
||||
p_ser.CurrentAllocationAddress(CELL_SPACE),
|
||||
p_ser.CurrentAllocationAddress(LO_SPACE));
|
||||
}
|
||||
|
||||
|
||||
DEPENDENT_TEST(ContextDeserialization, ContextSerialization) {
|
||||
if (!Snapshot::IsEnabled()) {
|
||||
int file_name_length = StrLength(FLAG_testing_serialization_file) + 10;
|
||||
Vector<char> startup_name = Vector<char>::New(file_name_length + 1);
|
||||
OS::SNPrintF(startup_name, "%s.startup", FLAG_testing_serialization_file);
|
||||
|
||||
CHECK(Snapshot::Initialize(startup_name.start()));
|
||||
|
||||
const char* file_name = FLAG_testing_serialization_file;
|
||||
ReserveSpaceForPartialSnapshot(file_name);
|
||||
|
||||
int snapshot_size = 0;
|
||||
byte* snapshot = ReadBytes(file_name, &snapshot_size);
|
||||
|
||||
Object* root;
|
||||
{
|
||||
SnapshotByteSource source(snapshot, snapshot_size);
|
||||
Deserializer deserializer(&source);
|
||||
deserializer.DeserializePartial(&root);
|
||||
CHECK(root->IsContext());
|
||||
}
|
||||
v8::HandleScope handle_scope;
|
||||
Handle<Object>root_handle(root);
|
||||
|
||||
Object* root2;
|
||||
{
|
||||
SnapshotByteSource source(snapshot, snapshot_size);
|
||||
Deserializer deserializer(&source);
|
||||
deserializer.DeserializePartial(&root2);
|
||||
CHECK(root2->IsContext());
|
||||
CHECK(*root_handle != root2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -463,6 +556,7 @@ DEPENDENT_TEST(PartialDeserialization, PartialSerialization) {
|
||||
TEST(LinearAllocation) {
|
||||
v8::V8::Initialize();
|
||||
int new_space_max = 512 * KB;
|
||||
|
||||
for (int size = 1000; size < 5 * MB; size += size >> 1) {
|
||||
int new_space_size = (size < new_space_max) ? size : new_space_max;
|
||||
Heap::ReserveSpace(
|
||||
|
@ -52,7 +52,7 @@ for (i = 0; i < scripts.length; i++) {
|
||||
}
|
||||
|
||||
// This has to be updated if the number of native scripts change.
|
||||
assertEquals(13, named_native_count);
|
||||
assertEquals(14, named_native_count);
|
||||
// If no snapshot is used, only the 'gc' extension is loaded.
|
||||
// If snapshot is used, all extensions are cached in the snapshot.
|
||||
assertTrue(extension_count == 1 || extension_count == 5);
|
||||
|
@ -573,12 +573,12 @@
|
||||
'../../src/math.js',
|
||||
'../../src/messages.js',
|
||||
'../../src/apinatives.js',
|
||||
'../../src/debug-delay.js',
|
||||
'../../src/liveedit-delay.js',
|
||||
'../../src/mirror-delay.js',
|
||||
'../../src/date-delay.js',
|
||||
'../../src/json-delay.js',
|
||||
'../../src/regexp-delay.js',
|
||||
'../../src/debug-debugger.js',
|
||||
'../../src/mirror-debugger.js',
|
||||
'../../src/liveedit-debugger.js',
|
||||
'../../src/date.js',
|
||||
'../../src/json.js',
|
||||
'../../src/regexp.js',
|
||||
'../../src/macros.py',
|
||||
],
|
||||
},
|
||||
|
@ -220,8 +220,8 @@ namespace internal {
|
||||
}
|
||||
|
||||
template <>
|
||||
int NativesCollection<%(type)s>::GetDelayCount() {
|
||||
return %(delay_count)i;
|
||||
int NativesCollection<%(type)s>::GetDebuggerCount() {
|
||||
return %(debugger_count)i;
|
||||
}
|
||||
|
||||
template <>
|
||||
@ -252,23 +252,23 @@ SOURCE_DECLARATION = """\
|
||||
"""
|
||||
|
||||
|
||||
GET_DELAY_INDEX_CASE = """\
|
||||
GET_DEBUGGER_INDEX_CASE = """\
|
||||
if (strcmp(name, "%(id)s") == 0) return %(i)i;
|
||||
"""
|
||||
|
||||
|
||||
GET_DELAY_SCRIPT_SOURCE_CASE = """\
|
||||
GET_DEBUGGER_SCRIPT_SOURCE_CASE = """\
|
||||
if (index == %(i)i) return Vector<const char>(%(id)s, %(length)i);
|
||||
"""
|
||||
|
||||
|
||||
GET_DELAY_SCRIPT_NAME_CASE = """\
|
||||
GET_DEBUGGER_SCRIPT_NAME_CASE = """\
|
||||
if (index == %(i)i) return Vector<const char>("%(name)s", %(length)i);
|
||||
"""
|
||||
|
||||
def JS2C(source, target, env):
|
||||
ids = []
|
||||
delay_ids = []
|
||||
debugger_ids = []
|
||||
modules = []
|
||||
# Locate the macros file name.
|
||||
consts = {}
|
||||
@ -287,7 +287,7 @@ def JS2C(source, target, env):
|
||||
source_lines_empty = []
|
||||
for module in modules:
|
||||
filename = str(module)
|
||||
delay = filename.endswith('-delay.js')
|
||||
debugger = filename.endswith('-debugger.js')
|
||||
lines = ReadFile(filename)
|
||||
lines = ExpandConstants(lines, consts)
|
||||
lines = ExpandMacros(lines, macros)
|
||||
@ -295,29 +295,29 @@ def JS2C(source, target, env):
|
||||
lines = minifier.JSMinify(lines)
|
||||
data = ToCArray(lines)
|
||||
id = (os.path.split(filename)[1])[:-3]
|
||||
if delay: id = id[:-6]
|
||||
if delay:
|
||||
delay_ids.append((id, len(lines)))
|
||||
if debugger: id = id[:-9]
|
||||
if debugger:
|
||||
debugger_ids.append((id, len(lines)))
|
||||
else:
|
||||
ids.append((id, len(lines)))
|
||||
source_lines.append(SOURCE_DECLARATION % { 'id': id, 'data': data })
|
||||
source_lines_empty.append(SOURCE_DECLARATION % { 'id': id, 'data': data })
|
||||
|
||||
# Build delay support functions
|
||||
# Build debugger support functions
|
||||
get_index_cases = [ ]
|
||||
get_script_source_cases = [ ]
|
||||
get_script_name_cases = [ ]
|
||||
|
||||
i = 0
|
||||
for (id, length) in delay_ids:
|
||||
for (id, length) in debugger_ids:
|
||||
native_name = "native %s.js" % id
|
||||
get_index_cases.append(GET_DELAY_INDEX_CASE % { 'id': id, 'i': i })
|
||||
get_script_source_cases.append(GET_DELAY_SCRIPT_SOURCE_CASE % {
|
||||
get_index_cases.append(GET_DEBUGGER_INDEX_CASE % { 'id': id, 'i': i })
|
||||
get_script_source_cases.append(GET_DEBUGGER_SCRIPT_SOURCE_CASE % {
|
||||
'id': id,
|
||||
'length': length,
|
||||
'i': i
|
||||
})
|
||||
get_script_name_cases.append(GET_DELAY_SCRIPT_NAME_CASE % {
|
||||
get_script_name_cases.append(GET_DEBUGGER_SCRIPT_NAME_CASE % {
|
||||
'name': native_name,
|
||||
'length': len(native_name),
|
||||
'i': i
|
||||
@ -326,13 +326,13 @@ def JS2C(source, target, env):
|
||||
|
||||
for (id, length) in ids:
|
||||
native_name = "native %s.js" % id
|
||||
get_index_cases.append(GET_DELAY_INDEX_CASE % { 'id': id, 'i': i })
|
||||
get_script_source_cases.append(GET_DELAY_SCRIPT_SOURCE_CASE % {
|
||||
get_index_cases.append(GET_DEBUGGER_INDEX_CASE % { 'id': id, 'i': i })
|
||||
get_script_source_cases.append(GET_DEBUGGER_SCRIPT_SOURCE_CASE % {
|
||||
'id': id,
|
||||
'length': length,
|
||||
'i': i
|
||||
})
|
||||
get_script_name_cases.append(GET_DELAY_SCRIPT_NAME_CASE % {
|
||||
get_script_name_cases.append(GET_DEBUGGER_SCRIPT_NAME_CASE % {
|
||||
'name': native_name,
|
||||
'length': len(native_name),
|
||||
'i': i
|
||||
@ -342,8 +342,8 @@ def JS2C(source, target, env):
|
||||
# Emit result
|
||||
output = open(str(target[0]), "w")
|
||||
output.write(HEADER_TEMPLATE % {
|
||||
'builtin_count': len(ids) + len(delay_ids),
|
||||
'delay_count': len(delay_ids),
|
||||
'builtin_count': len(ids) + len(debugger_ids),
|
||||
'debugger_count': len(debugger_ids),
|
||||
'source_lines': "\n".join(source_lines),
|
||||
'get_index_cases': "".join(get_index_cases),
|
||||
'get_script_source_cases': "".join(get_script_source_cases),
|
||||
@ -355,8 +355,8 @@ def JS2C(source, target, env):
|
||||
if len(target) > 1:
|
||||
output = open(str(target[1]), "w")
|
||||
output.write(HEADER_TEMPLATE % {
|
||||
'builtin_count': len(ids) + len(delay_ids),
|
||||
'delay_count': len(delay_ids),
|
||||
'builtin_count': len(ids) + len(debugger_ids),
|
||||
'debugger_count': len(debugger_ids),
|
||||
'source_lines': "\n".join(source_lines_empty),
|
||||
'get_index_cases': "".join(get_index_cases),
|
||||
'get_script_source_cases': "".join(get_script_source_cases),
|
||||
|
Loading…
Reference in New Issue
Block a user