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:
kasperl@chromium.org 2010-03-23 11:40:38 +00:00
parent c2427115db
commit 7d6a3b433f
60 changed files with 1276 additions and 795 deletions

View File

@ -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>());

View File

@ -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()

View File

@ -31,7 +31,7 @@
function CreateDate(time) {
var date = new ORIGINAL_DATE();
var date = new $Date();
date.setTime(time);
return date;
}

View File

@ -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__
}

View File

@ -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");

View File

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

View File

@ -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);

View File

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

View File

@ -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);
};

View File

@ -28,6 +28,7 @@
#include "v8.h"
#include "compilation-cache.h"
#include "serialize.h"
namespace v8 {
namespace internal {

View File

@ -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,

View File

@ -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")));

View File

@ -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")

View File

@ -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);
}

View File

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

View File

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

View File

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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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
View 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);
}

View File

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

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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");
}

View File

@ -2490,11 +2490,6 @@ bool JSFunction::IsBuiltin() {
}
bool JSObject::IsLoaded() {
return !map()->needs_loading();
}
Code* JSFunction::code() {
return shared()->code();
}

View File

@ -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;

View File

@ -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;

View File

@ -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");

View File

@ -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");

View File

@ -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");

View File

@ -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();

View File

@ -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:

View File

@ -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);

View File

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

View File

@ -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_

View File

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

View File

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

View File

@ -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);

View File

@ -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;
}

View File

@ -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();

View File

@ -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:

View File

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

View File

@ -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);

View File

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

View File

@ -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());

View File

@ -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;

View File

@ -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(

View File

@ -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);

View File

@ -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',
],
},

View File

@ -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),