diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-10-27 13:34:16 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-01-09 13:06:01 +0100 |
commit | 194da71eed49e4d5e904e8c28cb510fb85b95912 (patch) | |
tree | 4bb40c02292e8fe51c1e975b09727b710748668c | |
parent | 504ef4cafdbc0c927d9f86ef21d9e7db757fd110 (diff) | |
download | qtjsbackend-194da71eed49e4d5e904e8c28cb510fb85b95912.tar.gz |
[V8] Introduce a QML compilation mode
In QML mode, there is a second global object - known as the QML
global object. During property resolution, if a property is not
present on the JS global object, it is resolved on the QML global
object.
This global object behavior is only enabled if a script is being
compiled in QML mode. The object to use as the QML global object
is passed as a parameter to the Script::Run() method. Any function
closures etc. created during the run will retain a reference to this
object, so different objects can be passed in different script
runs.
Change-Id: I75d6f8173260e0d4933fd33ad16a277542048f09
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
60 files changed, 692 insertions, 153 deletions
diff --git a/src/3rdparty/v8/include/v8.h b/src/3rdparty/v8/include/v8.h index 87ba6ab..8fb22f8 100644 --- a/src/3rdparty/v8/include/v8.h +++ b/src/3rdparty/v8/include/v8.h @@ -611,6 +611,11 @@ class ScriptOrigin { */ class V8EXPORT Script { public: + enum CompileFlags { + Default = 0x00, + QmlMode = 0x01 + }; + /** * Compiles the specified script (context-independent). * @@ -629,7 +634,8 @@ class V8EXPORT Script { static Local<Script> New(Handle<String> source, ScriptOrigin* origin = NULL, ScriptData* pre_data = NULL, - Handle<String> script_data = Handle<String>()); + Handle<String> script_data = Handle<String>(), + CompileFlags = Default); /** * Compiles the specified script using the specified file name @@ -642,7 +648,8 @@ class V8EXPORT Script { * will use the currently entered context). */ static Local<Script> New(Handle<String> source, - Handle<Value> file_name); + Handle<Value> file_name, + CompileFlags = Default); /** * Compiles the specified script (bound to current context). @@ -663,7 +670,8 @@ class V8EXPORT Script { static Local<Script> Compile(Handle<String> source, ScriptOrigin* origin = NULL, ScriptData* pre_data = NULL, - Handle<String> script_data = Handle<String>()); + Handle<String> script_data = Handle<String>(), + CompileFlags = Default); /** * Compiles the specified script using the specified file name @@ -680,7 +688,8 @@ class V8EXPORT Script { */ static Local<Script> Compile(Handle<String> source, Handle<Value> file_name, - Handle<String> script_data = Handle<String>()); + Handle<String> script_data = Handle<String>(), + CompileFlags = Default); /** * Runs the script returning the resulting value. If the script is @@ -690,6 +699,7 @@ class V8EXPORT Script { * compiled. */ Local<Value> Run(); + Local<Value> Run(Handle<Object> qml); /** * Returns the script id value. @@ -3815,6 +3825,7 @@ class V8EXPORT Context { * JavaScript frames an empty handle is returned. */ static Local<Context> GetCalling(); + static Local<Object> GetCallingQmlGlobal(); /** * Sets the security token for the context. To access an object in diff --git a/src/3rdparty/v8/src/api.cc b/src/3rdparty/v8/src/api.cc index 6d3b319..f0e0810 100644 --- a/src/3rdparty/v8/src/api.cc +++ b/src/3rdparty/v8/src/api.cc @@ -1600,7 +1600,8 @@ ScriptData* ScriptData::New(const char* data, int length) { Local<Script> Script::New(v8::Handle<String> source, v8::ScriptOrigin* origin, v8::ScriptData* pre_data, - v8::Handle<String> script_data) { + v8::Handle<String> script_data, + v8::Script::CompileFlags compile_flags) { i::Isolate* isolate = i::Isolate::Current(); ON_BAILOUT(isolate, "v8::Script::New()", return Local<Script>()); LOG_API(isolate, "Script::New"); @@ -1642,7 +1643,8 @@ Local<Script> Script::New(v8::Handle<String> source, NULL, pre_data_impl, Utils::OpenHandle(*script_data, true), - i::NOT_NATIVES_CODE); + i::NOT_NATIVES_CODE, + compile_flags); has_pending_exception = result.is_null(); EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>()); raw_result = *result; @@ -1653,21 +1655,23 @@ Local<Script> Script::New(v8::Handle<String> source, Local<Script> Script::New(v8::Handle<String> source, - v8::Handle<Value> file_name) { + v8::Handle<Value> file_name, + v8::Script::CompileFlags compile_flags) { ScriptOrigin origin(file_name); - return New(source, &origin); + return New(source, &origin, 0, Handle<String>(), compile_flags); } Local<Script> Script::Compile(v8::Handle<String> source, v8::ScriptOrigin* origin, v8::ScriptData* pre_data, - v8::Handle<String> script_data) { + v8::Handle<String> script_data, + v8::Script::CompileFlags compile_flags) { i::Isolate* isolate = i::Isolate::Current(); ON_BAILOUT(isolate, "v8::Script::Compile()", return Local<Script>()); LOG_API(isolate, "Script::Compile"); ENTER_V8(isolate); - Local<Script> generic = New(source, origin, pre_data, script_data); + Local<Script> generic = New(source, origin, pre_data, script_data, compile_flags); if (generic.IsEmpty()) return generic; i::Handle<i::Object> obj = Utils::OpenHandle(*generic); @@ -1683,13 +1687,18 @@ Local<Script> Script::Compile(v8::Handle<String> source, Local<Script> Script::Compile(v8::Handle<String> source, v8::Handle<Value> file_name, - v8::Handle<String> script_data) { + v8::Handle<String> script_data, + v8::Script::CompileFlags compile_flags) { ScriptOrigin origin(file_name); - return Compile(source, &origin, 0, script_data); + return Compile(source, &origin, 0, script_data, compile_flags); } Local<Value> Script::Run() { + return Run(Handle<Object>()); +} + +Local<Value> Script::Run(Handle<Object> qml) { i::Isolate* isolate = i::Isolate::Current(); ON_BAILOUT(isolate, "v8::Script::Run()", return Local<Value>()); LOG_API(isolate, "Script::Run"); @@ -1708,10 +1717,11 @@ Local<Value> Script::Run() { fun = i::Handle<i::JSFunction>(i::JSFunction::cast(*obj), isolate); } EXCEPTION_PREAMBLE(isolate); + i::Handle<i::Object> qmlglobal = Utils::OpenHandle(*qml, true); i::Handle<i::Object> receiver( isolate->context()->global_proxy(), isolate); i::Handle<i::Object> result = - i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception); + i::Execution::Call(fun, receiver, 0, NULL, &has_pending_exception, false, qmlglobal); EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<Value>()); raw_result = *result; } @@ -4746,6 +4756,25 @@ v8::Local<v8::Context> Context::GetCalling() { } +v8::Local<v8::Object> Context::GetCallingQmlGlobal() { + i::Isolate* isolate = i::Isolate::Current(); + if (IsDeadCheck(isolate, "v8::Context::GetCallingQmlGlobal()")) { + return Local<Object>(); + } + + i::Context *context = isolate->context(); + i::JavaScriptFrameIterator it; + if (it.done()) return Local<Object>(); + context = i::Context::cast(it.frame()->context()); + if (!context->qml_global_object()->IsUndefined()) { + i::Handle<i::Object> qmlglobal(context->qml_global_object()); + return Utils::ToLocal(i::Handle<i::JSObject>::cast(qmlglobal)); + } else { + return Local<Object>(); + } +} + + v8::Local<v8::Object> Context::Global() { if (IsDeadCheck(i::Isolate::Current(), "v8::Context::Global()")) { return Local<v8::Object>(); diff --git a/src/3rdparty/v8/src/arm/code-stubs-arm.cc b/src/3rdparty/v8/src/arm/code-stubs-arm.cc index 1e73a55..cecc9d1 100644 --- a/src/3rdparty/v8/src/arm/code-stubs-arm.cc +++ b/src/3rdparty/v8/src/arm/code-stubs-arm.cc @@ -249,6 +249,10 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { __ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX))); __ str(r2, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); + // Copy the qml global object from the surrounding context. + __ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::QML_GLOBAL_OBJECT_INDEX))); + __ str(r1, MemOperand(r0, Context::SlotOffset(Context::QML_GLOBAL_OBJECT_INDEX))); + // Initialize the rest of the slots to undefined. __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { @@ -313,6 +317,10 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) { __ str(r1, ContextOperand(r0, Context::EXTENSION_INDEX)); __ str(r2, ContextOperand(r0, Context::GLOBAL_OBJECT_INDEX)); + // Copy the qml global object from the surrounding context. + __ ldr(r1, ContextOperand(cp, Context::QML_GLOBAL_OBJECT_INDEX)); + __ str(r1, ContextOperand(r0, Context::QML_GLOBAL_OBJECT_INDEX)); + // Initialize the rest of the slots to the hole value. __ LoadRoot(r1, Heap::kTheHoleValueRootIndex); for (int i = 0; i < slots_; i++) { diff --git a/src/3rdparty/v8/src/arm/full-codegen-arm.cc b/src/3rdparty/v8/src/arm/full-codegen-arm.cc index 03d5067..9a7b116 100644 --- a/src/3rdparty/v8/src/arm/full-codegen-arm.cc +++ b/src/3rdparty/v8/src/arm/full-codegen-arm.cc @@ -186,7 +186,8 @@ void FullCodeGenerator::Generate() { // Possibly allocate a local context. int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; - if (heap_slots > 0) { + if (heap_slots > 0 || + (scope()->is_qml_mode() && scope()->is_global_scope())) { // Argument to NewContext is the function, which is still in r1. Comment cmnt(masm_, "[ Allocate context"); __ push(r1); @@ -194,7 +195,7 @@ void FullCodeGenerator::Generate() { __ Push(info->scope()->GetScopeInfo()); __ CallRuntime(Runtime::kNewGlobalContext, 2); } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { - FastNewContextStub stub(heap_slots); + FastNewContextStub stub((heap_slots < 0) ? 0 : heap_slots); __ CallStub(&stub); } else { __ CallRuntime(Runtime::kNewFunctionContext, 1); @@ -812,6 +813,7 @@ void FullCodeGenerator::VisitVariableDeclaration( ? isolate()->factory()->the_hole_value() : isolate()->factory()->undefined_value(), zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); break; case Variable::PARAMETER: @@ -872,6 +874,7 @@ void FullCodeGenerator::VisitFunctionDeclaration( // Check for stack-overflow exception. if (function.is_null()) return SetStackOverflow(); globals_->Add(function, zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); break; } @@ -927,6 +930,7 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { Comment cmnt(masm_, "[ ModuleDeclaration"); globals_->Add(variable->name(), zone()); globals_->Add(instance, zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); Visit(declaration->module()); break; } @@ -1337,7 +1341,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, __ bind(&fast); } - __ ldr(r0, GlobalObjectOperand()); + __ ldr(r0, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); __ mov(r2, Operand(var->name())); RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) ? RelocInfo::CODE_TARGET @@ -1424,7 +1428,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Comment cmnt(masm_, "Global variable"); // Use inline caching. Variable name is passed in r2 and the global // object (receiver) in r0. - __ ldr(r0, GlobalObjectOperand()); + __ ldr(r0, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); __ mov(r2, Operand(var->name())); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); @@ -2092,7 +2096,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, if (var->IsUnallocated()) { // Global var, const, or let. __ mov(r2, Operand(var->name())); - __ ldr(r1, GlobalObjectOperand()); + __ ldr(r1, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); @@ -2360,8 +2364,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { __ mov(r1, Operand(Smi::FromInt(scope()->start_position()))); __ push(r1); + // Push the qml mode flag. + __ mov(r1, Operand(Smi::FromInt(is_qml_mode()))); + __ push(r1); + // Do the runtime call. - __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); + __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6); } @@ -2418,7 +2426,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { context()->DropAndPlug(1, r0); } else if (proxy != NULL && proxy->var()->IsUnallocated()) { // Push global object as receiver for the call IC. - __ ldr(r0, GlobalObjectOperand()); + __ ldr(r0, proxy->var()->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); __ push(r0); EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT); } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { @@ -3845,7 +3853,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { // but "delete this" is allowed. ASSERT(language_mode() == CLASSIC_MODE || var->is_this()); if (var->IsUnallocated()) { - __ ldr(r2, GlobalObjectOperand()); + __ ldr(r2, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); __ mov(r1, Operand(var->name())); __ mov(r0, Operand(Smi::FromInt(kNonStrictMode))); __ Push(r2, r1, r0); @@ -4149,7 +4157,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { VariableProxy* proxy = expr->AsVariableProxy(); if (proxy != NULL && proxy->var()->IsUnallocated()) { Comment cmnt(masm_, "Global variable"); - __ ldr(r0, GlobalObjectOperand()); + __ ldr(r0, proxy->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); __ mov(r2, Operand(proxy->name())); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); // Use a regular load, not a contextual load, to avoid a reference diff --git a/src/3rdparty/v8/src/arm/lithium-arm.cc b/src/3rdparty/v8/src/arm/lithium-arm.cc index 17f3325..b492d48 100644 --- a/src/3rdparty/v8/src/arm/lithium-arm.cc +++ b/src/3rdparty/v8/src/arm/lithium-arm.cc @@ -994,7 +994,7 @@ LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) { LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { LOperand* context = UseRegisterAtStart(instr->value()); - return DefineAsRegister(new(zone()) LGlobalObject(context)); + return DefineAsRegister(new(zone()) LGlobalObject(context, instr->qml_global())); } @@ -1068,7 +1068,7 @@ LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) { LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) { argument_count_ -= instr->argument_count(); - return MarkAsCall(DefineFixed(new(zone()) LCallGlobal, r0), instr); + return MarkAsCall(DefineFixed(new(zone()) LCallGlobal(instr->qml_global()), r0), instr); } diff --git a/src/3rdparty/v8/src/arm/lithium-arm.h b/src/3rdparty/v8/src/arm/lithium-arm.h index 0ba5e45..2c289dd 100644 --- a/src/3rdparty/v8/src/arm/lithium-arm.h +++ b/src/3rdparty/v8/src/arm/lithium-arm.h @@ -1542,13 +1542,18 @@ class LDeclareGlobals: public LTemplateInstruction<0, 0, 0> { class LGlobalObject: public LTemplateInstruction<1, 1, 0> { public: - explicit LGlobalObject(LOperand* context) { + explicit LGlobalObject(LOperand* context, bool qml_global) { inputs_[0] = context; + qml_global_ = qml_global; } DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") LOperand* context() { return inputs_[0]; } + bool qml_global() { return qml_global_; } + + private: + bool qml_global_; }; @@ -1644,10 +1649,16 @@ class LCallGlobal: public LTemplateInstruction<1, 0, 0> { DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call-global") DECLARE_HYDROGEN_ACCESSOR(CallGlobal) + explicit LCallGlobal(bool qml_global) : qml_global_(qml_global) {} + virtual void PrintDataTo(StringStream* stream); Handle<String> name() const {return hydrogen()->name(); } int arity() const { return hydrogen()->argument_count() - 1; } + + bool qml_global() { return qml_global_; } + private: + bool qml_global_; }; diff --git a/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc b/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc index 7615134..392c18e 100644 --- a/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc +++ b/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc @@ -175,12 +175,13 @@ bool LCodeGen::GeneratePrologue() { // Possibly allocate a local context. int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; - if (heap_slots > 0) { + if (heap_slots > 0 || + (scope()->is_qml_mode() && scope()->is_global_scope())) { Comment(";;; Allocate local context"); // Argument to NewContext is the function, which is in r1. __ push(r1); if (heap_slots <= FastNewContextStub::kMaximumSlots) { - FastNewContextStub stub(heap_slots); + FastNewContextStub stub((heap_slots < 0)?0:heap_slots); __ CallStub(&stub); } else { __ CallRuntime(Runtime::kNewFunctionContext, 1); @@ -3343,7 +3344,9 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { void LCodeGen::DoGlobalObject(LGlobalObject* instr) { Register result = ToRegister(instr->result()); - __ ldr(result, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); + __ ldr(result, ContextOperand(cp, instr->qml_global() + ? Context::QML_GLOBAL_OBJECT_INDEX + : Context::GLOBAL_OBJECT_INDEX)); } diff --git a/src/3rdparty/v8/src/arm/macro-assembler-arm.h b/src/3rdparty/v8/src/arm/macro-assembler-arm.h index 1d97a6c..0ff8579 100644 --- a/src/3rdparty/v8/src/arm/macro-assembler-arm.h +++ b/src/3rdparty/v8/src/arm/macro-assembler-arm.h @@ -1414,6 +1414,11 @@ inline MemOperand GlobalObjectOperand() { } +static inline MemOperand QmlGlobalObjectOperand() { + return ContextOperand(cp, Context::QML_GLOBAL_OBJECT_INDEX); +} + + #ifdef GENERATED_CODE_COVERAGE #define CODE_COVERAGE_STRINGIFY(x) #x #define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x) diff --git a/src/3rdparty/v8/src/ast.cc b/src/3rdparty/v8/src/ast.cc index 52990b8..3015b1e 100644 --- a/src/3rdparty/v8/src/ast.cc +++ b/src/3rdparty/v8/src/ast.cc @@ -173,6 +173,11 @@ LanguageMode FunctionLiteral::language_mode() const { } +QmlModeFlag FunctionLiteral::qml_mode_flag() const { + return scope()->qml_mode_flag(); +} + + ObjectLiteral::Property::Property(Literal* key, Expression* value, Isolate* isolate) { @@ -560,6 +565,11 @@ void Call::RecordTypeFeedback(TypeFeedbackOracle* oracle, is_monomorphic_ = oracle->CallIsMonomorphic(this); Property* property = expression()->AsProperty(); if (property == NULL) { + if (VariableProxy *proxy = expression()->AsVariableProxy()) { + if (proxy->var()->is_qml_global()) + return; + } + // Function call. Specialize for monomorphic calls. if (is_monomorphic_) target_ = oracle->GetCallTarget(this); } else { diff --git a/src/3rdparty/v8/src/ast.h b/src/3rdparty/v8/src/ast.h index 802ac65..d3f90b2 100644 --- a/src/3rdparty/v8/src/ast.h +++ b/src/3rdparty/v8/src/ast.h @@ -1961,6 +1961,8 @@ class FunctionLiteral: public Expression { bool is_anonymous() const { return IsAnonymous::decode(bitfield_); } bool is_classic_mode() const { return language_mode() == CLASSIC_MODE; } LanguageMode language_mode() const; + bool qml_mode() const { return qml_mode_flag() == kQmlMode; } + QmlModeFlag qml_mode_flag() const; int materialized_literal_count() { return materialized_literal_count_; } int expected_property_count() { return expected_property_count_; } diff --git a/src/3rdparty/v8/src/bootstrapper.cc b/src/3rdparty/v8/src/bootstrapper.cc index ffa5283..c06d73d 100644 --- a/src/3rdparty/v8/src/bootstrapper.cc +++ b/src/3rdparty/v8/src/bootstrapper.cc @@ -807,6 +807,7 @@ void Genesis::HookUpInnerGlobal(Handle<GlobalObject> inner_global) { Handle<JSBuiltinsObject> builtins_global(native_context_->builtins()); native_context_->set_extension(*inner_global); native_context_->set_global_object(*inner_global); + native_context_->set_qml_global_object(*inner_global); native_context_->set_security_token(*inner_global); static const PropertyAttributes attributes = static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE); @@ -832,6 +833,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, // Set extension and global object. native_context()->set_extension(*inner_global); native_context()->set_global_object(*inner_global); + native_context()->set_qml_global_object(*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 diff --git a/src/3rdparty/v8/src/code-stubs.h b/src/3rdparty/v8/src/code-stubs.h index e4384e7..8288f4d 100644 --- a/src/3rdparty/v8/src/code-stubs.h +++ b/src/3rdparty/v8/src/code-stubs.h @@ -344,7 +344,7 @@ class FastNewContextStub : public CodeStub { static const int kMaximumSlots = 64; explicit FastNewContextStub(int slots) : slots_(slots) { - ASSERT(slots_ > 0 && slots_ <= kMaximumSlots); + ASSERT(slots_ >= 0 && slots_ <= kMaximumSlots); } void Generate(MacroAssembler* masm); @@ -362,7 +362,7 @@ class FastNewBlockContextStub : public CodeStub { static const int kMaximumSlots = 64; explicit FastNewBlockContextStub(int slots) : slots_(slots) { - ASSERT(slots_ > 0 && slots_ <= kMaximumSlots); + ASSERT(slots_ >= 0 && slots_ <= kMaximumSlots); } void Generate(MacroAssembler* masm); diff --git a/src/3rdparty/v8/src/compiler.cc b/src/3rdparty/v8/src/compiler.cc index 710c61e..810794c 100644 --- a/src/3rdparty/v8/src/compiler.cc +++ b/src/3rdparty/v8/src/compiler.cc @@ -547,7 +547,8 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, v8::Extension* extension, ScriptDataImpl* pre_data, Handle<Object> script_data, - NativesFlag natives) { + NativesFlag natives, + v8::Script::CompileFlags compile_flags) { Isolate* isolate = source->GetIsolate(); int source_length = source->length(); isolate->counters()->total_load_size()->Increment(source_length); @@ -601,6 +602,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, if (FLAG_use_strict) { info.SetLanguageMode(FLAG_harmony_scoping ? EXTENDED_MODE : STRICT_MODE); } + if (compile_flags & v8::Script::QmlMode) info.MarkAsQmlMode(); result = MakeFunctionInfo(&info); if (extension == NULL && !result.is_null() && !result->dont_cache()) { compilation_cache->PutScript(source, context, result); @@ -621,7 +623,8 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, Handle<Context> context, bool is_global, LanguageMode language_mode, - int scope_position) { + int scope_position, + bool qml_mode) { Isolate* isolate = source->GetIsolate(); int source_length = source->length(); isolate->counters()->total_eval_size()->Increment(source_length); @@ -647,6 +650,7 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, info.MarkAsEval(); if (is_global) info.MarkAsGlobal(); info.SetLanguageMode(language_mode); + if (qml_mode) info.MarkAsQmlMode(); info.SetContext(context); result = MakeFunctionInfo(&info); if (!result.is_null()) { @@ -813,6 +817,12 @@ bool Compiler::CompileLazy(CompilationInfo* info) { info->SetLanguageMode(language_mode); shared->set_language_mode(language_mode); + // After parsing we know function's qml mode. Remember it. + if (info->function()->qml_mode()) { + shared->set_qml_mode(true); + info->MarkAsQmlMode(); + } + // Compile the code. if (!MakeCode(info)) { if (!isolate->has_pending_exception()) { @@ -1006,6 +1016,7 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info, function_info->set_allows_lazy_compilation_without_context( lit->AllowsLazyCompilationWithoutContext()); function_info->set_language_mode(lit->language_mode()); + function_info->set_qml_mode(lit->qml_mode()); function_info->set_uses_arguments(lit->scope()->arguments() != NULL); function_info->set_has_duplicate_parameters(lit->has_duplicate_parameters()); function_info->set_ast_node_count(lit->ast_node_count()); diff --git a/src/3rdparty/v8/src/compiler.h b/src/3rdparty/v8/src/compiler.h index af94595..b119775 100644 --- a/src/3rdparty/v8/src/compiler.h +++ b/src/3rdparty/v8/src/compiler.h @@ -63,6 +63,7 @@ class CompilationInfo { return LanguageModeField::decode(flags_); } bool is_in_loop() const { return IsInLoop::decode(flags_); } + bool is_qml_mode() const { return IsQmlMode::decode(flags_); } FunctionLiteral* function() const { return function_; } Scope* scope() const { return scope_; } Scope* global_scope() const { return global_scope_; } @@ -93,6 +94,9 @@ class CompilationInfo { ASSERT(is_lazy()); flags_ |= IsInLoop::encode(true); } + void MarkAsQmlMode() { + flags_ |= IsQmlMode::encode(true); + } void MarkAsNative() { flags_ |= IsNative::encode(true); } @@ -210,6 +214,9 @@ class CompilationInfo { ASSERT(language_mode() == CLASSIC_MODE); SetLanguageMode(shared_info_->language_mode()); } + if (!shared_info_.is_null() && shared_info_->qml_mode()) { + MarkAsQmlMode(); + } set_bailout_reason("unknown"); } @@ -237,7 +244,8 @@ class CompilationInfo { // If compiling for debugging produce just full code matching the // initial mode setting. class IsCompilingForDebugging: public BitField<bool, 8, 1> {}; - + // Qml mode + class IsQmlMode: public BitField<bool, 9, 1> {}; unsigned flags_; @@ -434,14 +442,16 @@ class Compiler : public AllStatic { v8::Extension* extension, ScriptDataImpl* pre_data, Handle<Object> script_data, - NativesFlag is_natives_code); + NativesFlag is_natives_code, + v8::Script::CompileFlags = v8::Script::Default); // Compile a String source within a context for Eval. static Handle<SharedFunctionInfo> CompileEval(Handle<String> source, Handle<Context> context, bool is_global, LanguageMode language_mode, - int scope_position); + int scope_position, + bool qml_mode); // Compile from function info (used for lazy compilation). Returns true on // success and false if the compilation resulted in a stack overflow. diff --git a/src/3rdparty/v8/src/contexts.cc b/src/3rdparty/v8/src/contexts.cc index fbb2f1a..662e326 100644 --- a/src/3rdparty/v8/src/contexts.cc +++ b/src/3rdparty/v8/src/contexts.cc @@ -103,6 +103,9 @@ Handle<Object> Context::Lookup(Handle<String> name, PrintF(")\n"); } + Handle<JSObject> qml_global; + Handle<JSObject> qml_global_global; + do { if (FLAG_trace_contexts) { PrintF(" - looking in context %p", reinterpret_cast<void*>(*context)); @@ -110,6 +113,11 @@ Handle<Object> Context::Lookup(Handle<String> name, PrintF("\n"); } + if (qml_global.is_null() && !context->qml_global_object()->IsUndefined()) { + qml_global = Handle<JSObject>(context->qml_global_object(), isolate); + qml_global_global = Handle<JSObject>(context->global_object(), isolate); + } + // 1. Check global objects, subjects of with, and extension objects. if (context->IsNativeContext() || context->IsWithContext() || @@ -233,6 +241,33 @@ Handle<Object> Context::Lookup(Handle<String> name, } } while (follow_context_chain); + if (!qml_global.is_null()) { + if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0) { + *attributes = qml_global_global->GetLocalPropertyAttribute(*name); + } else { + *attributes = qml_global_global->GetPropertyAttribute(*name); + } + + if (*attributes != ABSENT) { + *attributes = ABSENT; + } else { + if ((flags & FOLLOW_PROTOTYPE_CHAIN) == 0) { + *attributes = qml_global->GetLocalPropertyAttribute(*name); + } else { + *attributes = qml_global->GetPropertyAttribute(*name); + } + + if (*attributes != ABSENT) { + // property found + if (FLAG_trace_contexts) { + PrintF("=> found property in qml global object %p\n", + reinterpret_cast<void*>(*qml_global)); + } + return qml_global; + } + } + } + if (FLAG_trace_contexts) { PrintF("=> no property/slot found\n"); } diff --git a/src/3rdparty/v8/src/contexts.h b/src/3rdparty/v8/src/contexts.h index f44d15d..61e6c66 100644 --- a/src/3rdparty/v8/src/contexts.h +++ b/src/3rdparty/v8/src/contexts.h @@ -226,6 +226,7 @@ class Context: public FixedArray { // (with contexts), or the variable name (catch contexts), the serialized // scope info (block contexts), or the module instance (module contexts). EXTENSION_INDEX, + QML_GLOBAL_OBJECT_INDEX, GLOBAL_OBJECT_INDEX, MIN_CONTEXT_SLOTS, @@ -338,6 +339,13 @@ class Context: public FixedArray { set(GLOBAL_OBJECT_INDEX, object); } + JSObject* qml_global_object() { + return reinterpret_cast<JSObject *>(get(QML_GLOBAL_OBJECT_INDEX)); + } + void set_qml_global_object(JSObject *qml_global) { + set(QML_GLOBAL_OBJECT_INDEX, qml_global); + } + // Returns a JSGlobalProxy object or null. JSObject* global_proxy(); void set_global_proxy(JSObject* global); diff --git a/src/3rdparty/v8/src/execution.cc b/src/3rdparty/v8/src/execution.cc index 89091ba..913bf64 100644 --- a/src/3rdparty/v8/src/execution.cc +++ b/src/3rdparty/v8/src/execution.cc @@ -71,7 +71,8 @@ static Handle<Object> Invoke(bool is_construct, Handle<Object> receiver, int argc, Handle<Object> args[], - bool* has_pending_exception) { + bool* has_pending_exception, + Handle<Object> qml) { Isolate* isolate = function->GetIsolate(); // Entering JavaScript. @@ -102,6 +103,12 @@ static Handle<Object> Invoke(bool is_construct, // make the current one is indeed a global object. ASSERT(function->context()->global_object()->IsGlobalObject()); + Handle<JSObject> oldqml; + if (!qml.is_null()) { + oldqml = Handle<JSObject>(function->context()->qml_global_object()); + function->context()->set_qml_global_object(JSObject::cast(*qml)); + } + { // Save and restore context around invocation and block the // allocation of handles without explicit handle scopes. @@ -118,6 +125,9 @@ static Handle<Object> Invoke(bool is_construct, CALL_GENERATED_CODE(stub_entry, function_entry, func, recv, argc, argv); } + if (!qml.is_null()) + function->context()->set_qml_global_object(*oldqml); + #ifdef VERIFY_HEAP value->Verify(); #endif @@ -152,7 +162,19 @@ Handle<Object> Execution::Call(Handle<Object> callable, int argc, Handle<Object> argv[], bool* pending_exception, - bool convert_receiver) { + bool convert_receiver) +{ + return Call(callable, receiver, argc, argv, pending_exception, + convert_receiver, Handle<Object>()); +} + +Handle<Object> Execution::Call(Handle<Object> callable, + Handle<Object> receiver, + int argc, + Handle<Object> argv[], + bool* pending_exception, + bool convert_receiver, + Handle<Object> qml) { *pending_exception = false; if (!callable->IsJSFunction()) { @@ -176,7 +198,7 @@ Handle<Object> Execution::Call(Handle<Object> callable, if (*pending_exception) return callable; } - return Invoke(false, func, receiver, argc, argv, pending_exception); + return Invoke(false, func, receiver, argc, argv, pending_exception, qml); } @@ -185,7 +207,7 @@ Handle<Object> Execution::New(Handle<JSFunction> func, Handle<Object> argv[], bool* pending_exception) { return Invoke(true, func, Isolate::Current()->global_object(), argc, argv, - pending_exception); + pending_exception, Handle<Object>()); } @@ -204,7 +226,7 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func, *caught_exception = false; Handle<Object> result = Invoke(false, func, receiver, argc, args, - caught_exception); + caught_exception, Handle<Object>()); if (*caught_exception) { ASSERT(catcher.HasCaught()); diff --git a/src/3rdparty/v8/src/execution.h b/src/3rdparty/v8/src/execution.h index 9f5d9ff..90219f5 100644 --- a/src/3rdparty/v8/src/execution.h +++ b/src/3rdparty/v8/src/execution.h @@ -70,6 +70,14 @@ class Execution : public AllStatic { bool* pending_exception, bool convert_receiver = false); + static Handle<Object> Call(Handle<Object> callable, + Handle<Object> receiver, + int argc, + Handle<Object> argv[], + bool* pending_exception, + bool convert_receiver, + Handle<Object> qml); + // Construct object from function, the caller supplies an array of // arguments. Arguments are Object* type. After function returns, // pointers in 'args' might be invalid. diff --git a/src/3rdparty/v8/src/full-codegen.h b/src/3rdparty/v8/src/full-codegen.h index 89b51f9..972839e 100644 --- a/src/3rdparty/v8/src/full-codegen.h +++ b/src/3rdparty/v8/src/full-codegen.h @@ -572,6 +572,7 @@ class FullCodeGenerator: public AstVisitor { bool is_native() { return info_->is_native(); } bool is_classic_mode() { return language_mode() == CLASSIC_MODE; } LanguageMode language_mode() { return function()->language_mode(); } + bool is_qml_mode() { return function()->qml_mode(); } FunctionLiteral* function() { return info_->function(); } Scope* scope() { return scope_; } diff --git a/src/3rdparty/v8/src/globals.h b/src/3rdparty/v8/src/globals.h index babffbf..e8c323c 100644 --- a/src/3rdparty/v8/src/globals.h +++ b/src/3rdparty/v8/src/globals.h @@ -399,6 +399,12 @@ enum StrictModeFlag { kStrictMode }; +// The QML Compilation Mode +enum QmlModeFlag { + kNonQmlMode, + kQmlMode +}; + } } // namespace v8::internal diff --git a/src/3rdparty/v8/src/heap.cc b/src/3rdparty/v8/src/heap.cc index d56f01b..ebf3ccd 100644 --- a/src/3rdparty/v8/src/heap.cc +++ b/src/3rdparty/v8/src/heap.cc @@ -5149,6 +5149,7 @@ MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) { context->set_previous(function->context()); context->set_extension(Smi::FromInt(0)); context->set_global_object(function->context()->global_object()); + context->set_qml_global_object(function->context()->qml_global_object()); return context; } @@ -5169,6 +5170,7 @@ MaybeObject* Heap::AllocateCatchContext(JSFunction* function, context->set_previous(previous); context->set_extension(name); context->set_global_object(previous->global_object()); + context->set_qml_global_object(previous->qml_global_object()); context->set(Context::THROWN_OBJECT_INDEX, thrown_object); return context; } @@ -5187,6 +5189,7 @@ MaybeObject* Heap::AllocateWithContext(JSFunction* function, context->set_previous(previous); context->set_extension(extension); context->set_global_object(previous->global_object()); + context->set_qml_global_object(previous->qml_global_object()); return context; } @@ -5205,6 +5208,7 @@ MaybeObject* Heap::AllocateBlockContext(JSFunction* function, context->set_previous(previous); context->set_extension(scope_info); context->set_global_object(previous->global_object()); + context->set_qml_global_object(previous->qml_global_object()); return context; } diff --git a/src/3rdparty/v8/src/hydrogen-instructions.cc b/src/3rdparty/v8/src/hydrogen-instructions.cc index f93b930..c8edcff 100644 --- a/src/3rdparty/v8/src/hydrogen-instructions.cc +++ b/src/3rdparty/v8/src/hydrogen-instructions.cc @@ -700,6 +700,11 @@ void HCallNamed::PrintDataTo(StringStream* stream) { } +void HGlobalObject::PrintDataTo(StringStream* stream) { + stream->Add("qml_global: %s ", qml_global()?"true":"false"); + HUnaryOperation::PrintDataTo(stream); +} + void HCallGlobal::PrintDataTo(StringStream* stream) { stream->Add("%o ", *name()); HUnaryCall::PrintDataTo(stream); diff --git a/src/3rdparty/v8/src/hydrogen-instructions.h b/src/3rdparty/v8/src/hydrogen-instructions.h index d118354..7136657 100644 --- a/src/3rdparty/v8/src/hydrogen-instructions.h +++ b/src/3rdparty/v8/src/hydrogen-instructions.h @@ -1602,22 +1602,31 @@ class HDeclareGlobals: public HUnaryOperation { class HGlobalObject: public HUnaryOperation { public: - explicit HGlobalObject(HValue* context) : HUnaryOperation(context) { + explicit HGlobalObject(HValue* context) : HUnaryOperation(context), qml_global_(false) { set_representation(Representation::Tagged()); SetFlag(kUseGVN); } + virtual void PrintDataTo(StringStream* stream); + DECLARE_CONCRETE_INSTRUCTION(GlobalObject) virtual Representation RequiredInputRepresentation(int index) { return Representation::Tagged(); } + bool qml_global() { return qml_global_; } + void set_qml_global(bool v) { qml_global_ = v; } + protected: - virtual bool DataEquals(HValue* other) { return true; } + virtual bool DataEquals(HValue* other) { + HGlobalObject* o = HGlobalObject::cast(other); + return o->qml_global_ == qml_global_; + } private: virtual bool IsDeletable() const { return true; } + bool qml_global_; }; @@ -1812,7 +1821,7 @@ class HCallFunction: public HBinaryCall { class HCallGlobal: public HUnaryCall { public: HCallGlobal(HValue* context, Handle<String> name, int argument_count) - : HUnaryCall(context, argument_count), name_(name) { + : HUnaryCall(context, argument_count), name_(name), qml_global_(false) { } virtual void PrintDataTo(StringStream* stream); @@ -1824,10 +1833,14 @@ class HCallGlobal: public HUnaryCall { return Representation::Tagged(); } + bool qml_global() { return qml_global_; } + void set_qml_global(bool v) { qml_global_ = v; } + DECLARE_CONCRETE_INSTRUCTION(CallGlobal) private: Handle<String> name_; + bool qml_global_; }; diff --git a/src/3rdparty/v8/src/hydrogen.cc b/src/3rdparty/v8/src/hydrogen.cc index 51ae7f5..043d567 100644 --- a/src/3rdparty/v8/src/hydrogen.cc +++ b/src/3rdparty/v8/src/hydrogen.cc @@ -4823,6 +4823,7 @@ void HGraphBuilder::VisitVariableProxy(VariableProxy* expr) { } else { HValue* context = environment()->LookupContext(); HGlobalObject* global_object = new(zone()) HGlobalObject(context); + if (variable->is_qml_global()) global_object->set_qml_global(true); AddInstruction(global_object); HLoadGlobalGeneric* instr = new(zone()) HLoadGlobalGeneric(context, @@ -5596,6 +5597,7 @@ void HGraphBuilder::HandleGlobalVariableAssignment(Variable* var, } else { HValue* context = environment()->LookupContext(); HGlobalObject* global_object = new(zone()) HGlobalObject(context); + if (var->is_qml_global()) global_object->set_qml_global(true); AddInstruction(global_object); HStoreGlobalGeneric* instr = new(zone()) HStoreGlobalGeneric(context, @@ -7662,11 +7664,13 @@ void HGraphBuilder::VisitCall(Call* expr) { } else { HValue* context = environment()->LookupContext(); HGlobalObject* receiver = new(zone()) HGlobalObject(context); + if (var->is_qml_global()) receiver->set_qml_global(true); AddInstruction(receiver); PushAndAdd(new(zone()) HPushArgument(receiver)); CHECK_ALIVE(VisitArgumentList(expr->arguments())); call = new(zone()) HCallGlobal(context, var->name(), argument_count); + if (var->is_qml_global()) static_cast<HCallGlobal*>(call)->set_qml_global(true); Drop(argument_count); } @@ -8824,6 +8828,7 @@ void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* declaration) { globals_.Add(variable->binding_needs_init() ? isolate()->factory()->the_hole_value() : isolate()->factory()->undefined_value(), zone()); + globals_.Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); return; case Variable::PARAMETER: case Variable::LOCAL: @@ -8859,6 +8864,7 @@ void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* declaration) { // Check for stack-overflow exception. if (function.is_null()) return SetStackOverflow(); globals_.Add(function, zone()); + globals_.Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); return; } case Variable::PARAMETER: diff --git a/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc b/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc index 7ea71e4..5791095 100644 --- a/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc +++ b/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc @@ -220,6 +220,11 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)), ebx); + // Copy the qml global object from the previous context. + __ mov(ebx, Operand(esi, Context::SlotOffset(Context::QML_GLOBAL_OBJECT_INDEX))); + __ mov(Operand(eax, Context::SlotOffset(Context::QML_GLOBAL_OBJECT_INDEX)), ebx); + + // Initialize the rest of the slots to undefined. __ mov(ebx, factory->undefined_value()); for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { @@ -286,6 +291,10 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) { __ mov(ebx, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX)); __ mov(ContextOperand(eax, Context::GLOBAL_OBJECT_INDEX), ebx); + // Copy the qml global object from the previous context. + __ mov(ebx, ContextOperand(esi, Context::QML_GLOBAL_OBJECT_INDEX)); + __ mov(ContextOperand(eax, Context::QML_GLOBAL_OBJECT_INDEX), ebx); + // Initialize the rest of the slots to the hole value. if (slots_ == 1) { __ mov(ContextOperand(eax, Context::MIN_CONTEXT_SLOTS), diff --git a/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc b/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc index 159c2ca..c58f242 100644 --- a/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc +++ b/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc @@ -181,7 +181,8 @@ void FullCodeGenerator::Generate() { // Possibly allocate a local context. int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; - if (heap_slots > 0) { + if (heap_slots > 0 || + (scope()->is_qml_mode() && scope()->is_global_scope())) { Comment cmnt(masm_, "[ Allocate context"); // Argument to NewContext is the function, which is still in edi. __ push(edi); @@ -189,7 +190,7 @@ void FullCodeGenerator::Generate() { __ Push(info->scope()->GetScopeInfo()); __ CallRuntime(Runtime::kNewGlobalContext, 2); } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { - FastNewContextStub stub(heap_slots); + FastNewContextStub stub((heap_slots < 0) ? 0 : heap_slots); __ CallStub(&stub); } else { __ CallRuntime(Runtime::kNewFunctionContext, 1); @@ -787,6 +788,7 @@ void FullCodeGenerator::VisitVariableDeclaration( globals_->Add(variable->binding_needs_init() ? isolate()->factory()->the_hole_value() : isolate()->factory()->undefined_value(), zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); break; case Variable::PARAMETER: @@ -846,6 +848,7 @@ void FullCodeGenerator::VisitFunctionDeclaration( // Check for stack-overflow exception. if (function.is_null()) return SetStackOverflow(); globals_->Add(function, zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); break; } @@ -898,6 +901,7 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { Comment cmnt(masm_, "[ ModuleDeclaration"); globals_->Add(variable->name(), zone()); globals_->Add(instance, zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); Visit(declaration->module()); break; } @@ -1295,7 +1299,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, // All extension objects were empty and it is safe to use a global // load IC call. - __ mov(edx, GlobalObjectOperand()); + __ mov(edx, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); __ mov(ecx, var->name()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) @@ -1379,7 +1383,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Comment cmnt(masm_, "Global variable"); // Use inline caching. Variable name is passed in ecx and the global // object in eax. - __ mov(edx, GlobalObjectOperand()); + __ mov(edx, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); __ mov(ecx, var->name()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); @@ -2048,7 +2052,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, if (var->IsUnallocated()) { // Global var, const, or let. __ mov(ecx, var->name()); - __ mov(edx, GlobalObjectOperand()); + __ mov(edx, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); @@ -2312,8 +2316,11 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { // Push the start position of the scope the calls resides in. __ push(Immediate(Smi::FromInt(scope()->start_position()))); + // Push the qml mode flag + __ push(Immediate(Smi::FromInt(is_qml_mode()))); + // Do the runtime call. - __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); + __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6); } @@ -2366,7 +2373,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { } else if (proxy != NULL && proxy->var()->IsUnallocated()) { // Push global object as receiver for the call IC. - __ push(GlobalObjectOperand()); + __ push(proxy->var()->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT); } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { @@ -3823,7 +3830,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { // but "delete this" is allowed. ASSERT(language_mode() == CLASSIC_MODE || var->is_this()); if (var->IsUnallocated()) { - __ push(GlobalObjectOperand()); + __ push(var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); __ push(Immediate(var->name())); __ push(Immediate(Smi::FromInt(kNonStrictMode))); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); @@ -4145,7 +4152,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { if (proxy != NULL && proxy->var()->IsUnallocated()) { Comment cmnt(masm_, "Global variable"); - __ mov(edx, GlobalObjectOperand()); + __ mov(edx, proxy->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); __ mov(ecx, Immediate(proxy->name())); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); // Use a regular load, not a contextual load, to avoid a reference diff --git a/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.cc b/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.cc index 676e73e..34ce1cd 100644 --- a/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.cc +++ b/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.cc @@ -241,12 +241,13 @@ bool LCodeGen::GeneratePrologue() { // Possibly allocate a local context. int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; - if (heap_slots > 0) { + if (heap_slots > 0 || + (scope()->is_qml_mode() && scope()->is_global_scope())) { Comment(";;; Allocate local context"); // Argument to NewContext is the function, which is still in edi. __ push(edi); if (heap_slots <= FastNewContextStub::kMaximumSlots) { - FastNewContextStub stub(heap_slots); + FastNewContextStub stub((heap_slots < 0)?0:heap_slots); __ CallStub(&stub); } else { __ CallRuntime(Runtime::kNewFunctionContext, 1); @@ -3126,7 +3127,9 @@ void LCodeGen::DoGlobalObject(LGlobalObject* instr) { Register context = ToRegister(instr->context()); Register result = ToRegister(instr->result()); __ mov(result, - Operand(context, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); + Operand(context, Context::SlotOffset(instr->qml_global() + ? Context::QML_GLOBAL_OBJECT_INDEX + : Context::GLOBAL_OBJECT_INDEX))); } diff --git a/src/3rdparty/v8/src/ia32/lithium-ia32.cc b/src/3rdparty/v8/src/ia32/lithium-ia32.cc index ba9c97e..dcc5b77 100644 --- a/src/3rdparty/v8/src/ia32/lithium-ia32.cc +++ b/src/3rdparty/v8/src/ia32/lithium-ia32.cc @@ -1035,7 +1035,7 @@ LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) { LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { LOperand* context = UseRegisterAtStart(instr->value()); - return DefineAsRegister(new(zone()) LGlobalObject(context)); + return DefineAsRegister(new(zone()) LGlobalObject(context, instr->qml_global())); } @@ -1125,7 +1125,7 @@ LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) { LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) { LOperand* context = UseFixed(instr->context(), esi); argument_count_ -= instr->argument_count(); - LCallGlobal* result = new(zone()) LCallGlobal(context); + LCallGlobal* result = new(zone()) LCallGlobal(context, instr->qml_global()); return MarkAsCall(DefineFixed(result, eax), instr); } diff --git a/src/3rdparty/v8/src/ia32/lithium-ia32.h b/src/3rdparty/v8/src/ia32/lithium-ia32.h index 18741d1..a1adb01 100644 --- a/src/3rdparty/v8/src/ia32/lithium-ia32.h +++ b/src/3rdparty/v8/src/ia32/lithium-ia32.h @@ -1603,13 +1603,19 @@ class LDeclareGlobals: public LTemplateInstruction<0, 1, 0> { class LGlobalObject: public LTemplateInstruction<1, 1, 0> { public: - explicit LGlobalObject(LOperand* context) { + explicit LGlobalObject(LOperand* context, bool qml_global) { inputs_[0] = context; + qml_global_ = qml_global; } LOperand* context() { return inputs_[0]; } DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") + + bool qml_global() { return qml_global_; } + + private: + bool qml_global_; }; @@ -1713,7 +1719,7 @@ class LCallFunction: public LTemplateInstruction<1, 2, 0> { class LCallGlobal: public LTemplateInstruction<1, 1, 0> { public: - explicit LCallGlobal(LOperand* context) { + explicit LCallGlobal(LOperand* context, bool qml_global) : qml_global_(qml_global) { inputs_[0] = context; } @@ -1726,6 +1732,10 @@ class LCallGlobal: public LTemplateInstruction<1, 1, 0> { Handle<String> name() const {return hydrogen()->name(); } int arity() const { return hydrogen()->argument_count() - 1; } + + bool qml_global() { return qml_global_; } + private: + bool qml_global_; }; diff --git a/src/3rdparty/v8/src/ia32/macro-assembler-ia32.h b/src/3rdparty/v8/src/ia32/macro-assembler-ia32.h index e48d0e7..b91cfcd 100644 --- a/src/3rdparty/v8/src/ia32/macro-assembler-ia32.h +++ b/src/3rdparty/v8/src/ia32/macro-assembler-ia32.h @@ -975,6 +975,9 @@ inline Operand GlobalObjectOperand() { return ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX); } +static inline Operand QmlGlobalObjectOperand() { + return ContextOperand(esi, Context::QML_GLOBAL_OBJECT_INDEX); +} // Generates an Operand for saving parameters after PrepareCallApiFunction. Operand ApiParameterOperand(int index); diff --git a/src/3rdparty/v8/src/ic.cc b/src/3rdparty/v8/src/ic.cc index 5cc213f..354ed64 100644 --- a/src/3rdparty/v8/src/ic.cc +++ b/src/3rdparty/v8/src/ic.cc @@ -677,7 +677,7 @@ Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup, // applicable. if (!holder.is_identical_to(receiver)) return Handle<Code>::null(); return isolate()->stub_cache()->ComputeCallNormal( - argc, kind_, extra_state); + argc, kind_, extra_state, IsQmlGlobal(holder)); } break; } diff --git a/src/3rdparty/v8/src/ic.h b/src/3rdparty/v8/src/ic.h index 8767f98..389c845 100644 --- a/src/3rdparty/v8/src/ic.h +++ b/src/3rdparty/v8/src/ic.h @@ -110,10 +110,16 @@ class IC { // object that contains this IC site. RelocInfo::Mode ComputeMode(); + bool IsQmlGlobal(Handle<Object> receiver) { + JSObject* qml_global = isolate_->context()->qml_global_object(); + return !qml_global->IsUndefined() && qml_global == *receiver; + } + // Returns if this IC is for contextual (no explicit receiver) // access to properties. bool IsContextual(Handle<Object> receiver) { - if (receiver->IsGlobalObject()) { + if (receiver->IsGlobalObject() || + IsQmlGlobal(receiver)) { return SlowIsContextual(); } else { ASSERT(!SlowIsContextual()); diff --git a/src/3rdparty/v8/src/mips/code-stubs-mips.cc b/src/3rdparty/v8/src/mips/code-stubs-mips.cc index 7f7d70e..f122d14 100644 --- a/src/3rdparty/v8/src/mips/code-stubs-mips.cc +++ b/src/3rdparty/v8/src/mips/code-stubs-mips.cc @@ -251,6 +251,11 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { __ sw(a1, MemOperand(v0, Context::SlotOffset(Context::EXTENSION_INDEX))); __ sw(a2, MemOperand(v0, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); + // Copy the qml global object from the surrounding context. + __ lw(a1, MemOperand(cp, Context::SlotOffset(Context::QML_GLOBAL_OBJECT_INDEX))); + __ sw(a1, MemOperand(v0, Context::SlotOffset(Context::QML_GLOBAL_OBJECT_INDEX))); + + // Initialize the rest of the slots to undefined. __ LoadRoot(a1, Heap::kUndefinedValueRootIndex); for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { @@ -313,6 +318,10 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) { __ sw(a1, ContextOperand(v0, Context::EXTENSION_INDEX)); __ sw(a2, ContextOperand(v0, Context::GLOBAL_OBJECT_INDEX)); + // Copy the qml global object from the surrounding context. + __ lw(a1, ContextOperand(cp, Context::QML_GLOBAL_OBJECT_INDEX)); + __ sw(a1, ContextOperand(v0, Context::QML_GLOBAL_OBJECT_INDEX)); + // Initialize the rest of the slots to the hole value. __ LoadRoot(a1, Heap::kTheHoleValueRootIndex); for (int i = 0; i < slots_; i++) { diff --git a/src/3rdparty/v8/src/mips/full-codegen-mips.cc b/src/3rdparty/v8/src/mips/full-codegen-mips.cc index 3e89fb4..46c9ecb 100644 --- a/src/3rdparty/v8/src/mips/full-codegen-mips.cc +++ b/src/3rdparty/v8/src/mips/full-codegen-mips.cc @@ -191,7 +191,8 @@ void FullCodeGenerator::Generate() { // Possibly allocate a local context. int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; - if (heap_slots > 0) { + if (heap_slots > 0 || + (scope()->is_qml_mode() && scope()->is_global_scope())) { Comment cmnt(masm_, "[ Allocate context"); // Argument to NewContext is the function, which is still in a1. __ push(a1); @@ -199,7 +200,7 @@ void FullCodeGenerator::Generate() { __ Push(info->scope()->GetScopeInfo()); __ CallRuntime(Runtime::kNewGlobalContext, 2); } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { - FastNewContextStub stub(heap_slots); + FastNewContextStub stub((heap_slots < 0) ? 0 : heap_slots); __ CallStub(&stub); } else { __ CallRuntime(Runtime::kNewFunctionContext, 1); @@ -823,6 +824,7 @@ void FullCodeGenerator::VisitVariableDeclaration( ? isolate()->factory()->the_hole_value() : isolate()->factory()->undefined_value(), zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); break; case Variable::PARAMETER: @@ -884,6 +886,7 @@ void FullCodeGenerator::VisitFunctionDeclaration( // Check for stack-overflow exception. if (function.is_null()) return SetStackOverflow(); globals_->Add(function, zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); break; } @@ -939,6 +942,7 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { Comment cmnt(masm_, "[ ModuleDeclaration"); globals_->Add(variable->name(), zone()); globals_->Add(instance, zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); Visit(declaration->module()); break; } @@ -1344,7 +1348,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, __ bind(&fast); } - __ lw(a0, GlobalObjectOperand()); + __ lw(a0, var->is_qml_global() ? QmlGlobalObjectOperand():GlobalObjectOperand()); __ li(a2, Operand(var->name())); RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) ? RelocInfo::CODE_TARGET @@ -1431,7 +1435,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { Comment cmnt(masm_, "Global variable"); // Use inline caching. Variable name is passed in a2 and the global // object (receiver) in a0. - __ lw(a0, GlobalObjectOperand()); + __ lw(a0, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); __ li(a2, Operand(var->name())); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); @@ -2111,7 +2115,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, // Global var, const, or let. __ mov(a0, result_register()); __ li(a2, Operand(var->name())); - __ lw(a1, GlobalObjectOperand()); + __ lw(a1, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); @@ -2385,8 +2389,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { __ li(a1, Operand(Smi::FromInt(scope()->start_position()))); __ push(a1); + // Push the qml mode flag. + __ li(a1, Operand(Smi::FromInt(is_qml_mode()))); + __ push(a1); + // Do the runtime call. - __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); + __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6); } @@ -2442,7 +2450,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { context()->DropAndPlug(1, v0); } else if (proxy != NULL && proxy->var()->IsUnallocated()) { // Push global object as receiver for the call IC. - __ lw(a0, GlobalObjectOperand()); + __ lw(a0, proxy->var()->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); __ push(a0); EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT); } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { @@ -3881,7 +3889,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { // but "delete this" is allowed. ASSERT(language_mode() == CLASSIC_MODE || var->is_this()); if (var->IsUnallocated()) { - __ lw(a2, GlobalObjectOperand()); + __ lw(a2, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); __ li(a1, Operand(var->name())); __ li(a0, Operand(Smi::FromInt(kNonStrictMode))); __ Push(a2, a1, a0); @@ -4188,7 +4196,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { VariableProxy* proxy = expr->AsVariableProxy(); if (proxy != NULL && proxy->var()->IsUnallocated()) { Comment cmnt(masm_, "Global variable"); - __ lw(a0, GlobalObjectOperand()); + __ lw(a0, proxy->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); __ li(a2, Operand(proxy->name())); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); // Use a regular load, not a contextual load, to avoid a reference diff --git a/src/3rdparty/v8/src/mips/lithium-codegen-mips.cc b/src/3rdparty/v8/src/mips/lithium-codegen-mips.cc index f79208e..b268fb3 100644 --- a/src/3rdparty/v8/src/mips/lithium-codegen-mips.cc +++ b/src/3rdparty/v8/src/mips/lithium-codegen-mips.cc @@ -165,12 +165,13 @@ bool LCodeGen::GeneratePrologue() { // Possibly allocate a local context. int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; - if (heap_slots > 0) { + if (heap_slots > 0 || + (scope()->is_qml_mode() && scope()->is_global_scope())) { Comment(";;; Allocate local context"); // Argument to NewContext is the function, which is in a1. __ push(a1); if (heap_slots <= FastNewContextStub::kMaximumSlots) { - FastNewContextStub stub(heap_slots); + FastNewContextStub stub((heap_slots < 0)?0:heap_slots); __ CallStub(&stub); } else { __ CallRuntime(Runtime::kNewFunctionContext, 1); @@ -3039,7 +3040,9 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { void LCodeGen::DoGlobalObject(LGlobalObject* instr) { Register result = ToRegister(instr->result()); - __ lw(result, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX)); + __ lw(result, ContextOperand(cp, instr->qml_global() + ? Context::QML_GLOBAL_OBJECT_INDEX + : Context::GLOBAL_OBJECT_INDEX)); } diff --git a/src/3rdparty/v8/src/mips/lithium-mips.cc b/src/3rdparty/v8/src/mips/lithium-mips.cc index b5eb128..7b71758 100644 --- a/src/3rdparty/v8/src/mips/lithium-mips.cc +++ b/src/3rdparty/v8/src/mips/lithium-mips.cc @@ -992,7 +992,7 @@ LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) { LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { LOperand* context = UseRegisterAtStart(instr->value()); - return DefineAsRegister(new(zone()) LGlobalObject(context)); + return DefineAsRegister(new(zone()) LGlobalObject(context, instr->qml_global())); } @@ -1067,7 +1067,7 @@ LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) { LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) { argument_count_ -= instr->argument_count(); - return MarkAsCall(DefineFixed(new(zone()) LCallGlobal, v0), instr); + return MarkAsCall(DefineFixed(new(zone()) LCallGlobal(instr->qml_global()), v0), instr); } diff --git a/src/3rdparty/v8/src/mips/lithium-mips.h b/src/3rdparty/v8/src/mips/lithium-mips.h index 3ea0aef..00e21fd 100644 --- a/src/3rdparty/v8/src/mips/lithium-mips.h +++ b/src/3rdparty/v8/src/mips/lithium-mips.h @@ -1522,13 +1522,19 @@ class LDeclareGlobals: public LTemplateInstruction<0, 0, 0> { class LGlobalObject: public LTemplateInstruction<1, 1, 0> { public: - explicit LGlobalObject(LOperand* context) { + explicit LGlobalObject(LOperand* context, bool qml_global) { inputs_[0] = context; + qml_global_ = qml_global; } LOperand* context() { return inputs_[0]; } DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") + + bool qml_global() { return qml_global_; } + + private: + bool qml_global_; }; @@ -1624,10 +1630,16 @@ class LCallGlobal: public LTemplateInstruction<1, 0, 0> { DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call-global") DECLARE_HYDROGEN_ACCESSOR(CallGlobal) + explicit LCallGlobal(bool qml_global) : qml_global_(qml_global) {} + virtual void PrintDataTo(StringStream* stream); Handle<String> name() const {return hydrogen()->name(); } int arity() const { return hydrogen()->argument_count() - 1; } + + bool qml_global() { return qml_global_; } + private: + bool qml_global_; }; diff --git a/src/3rdparty/v8/src/mips/macro-assembler-mips.h b/src/3rdparty/v8/src/mips/macro-assembler-mips.h index b57e514..8b7d7c1 100644 --- a/src/3rdparty/v8/src/mips/macro-assembler-mips.h +++ b/src/3rdparty/v8/src/mips/macro-assembler-mips.h @@ -112,6 +112,11 @@ inline MemOperand GlobalObjectOperand() { } +static inline MemOperand QmlGlobalObjectOperand() { + return ContextOperand(cp, Context::QML_GLOBAL_OBJECT_INDEX); +} + + // Generate a MemOperand for loading a field from an object. inline MemOperand FieldMemOperand(Register object, int offset) { return MemOperand(object, offset - kHeapObjectTag); diff --git a/src/3rdparty/v8/src/objects-inl.h b/src/3rdparty/v8/src/objects-inl.h index d0c225f..27a56dd 100644 --- a/src/3rdparty/v8/src/objects-inl.h +++ b/src/3rdparty/v8/src/objects-inl.h @@ -4170,6 +4170,8 @@ bool SharedFunctionInfo::is_classic_mode() { BOOL_GETTER(SharedFunctionInfo, compiler_hints, is_extended_mode, kExtendedModeFunction) +BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, qml_mode, + kQmlModeFunction) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, native, kNative) BOOL_ACCESSORS(SharedFunctionInfo, compiler_hints, name_should_print_as_anonymous, diff --git a/src/3rdparty/v8/src/objects.h b/src/3rdparty/v8/src/objects.h index 17ebc97..4854989 100644 --- a/src/3rdparty/v8/src/objects.h +++ b/src/3rdparty/v8/src/objects.h @@ -3469,6 +3469,9 @@ class ScopeInfo : public FixedArray { // Return the language mode of this scope. LanguageMode language_mode(); + // Is this scope a qml mode scope? + bool IsQmlMode(); + // Does this scope make a non-strict eval call? bool CallsNonStrictEval() { return CallsEval() && (language_mode() == CLASSIC_MODE); @@ -3491,7 +3494,7 @@ class ScopeInfo : public FixedArray { // 3. One context slot for the function name if it is context allocated. // Parameters allocated in the context count as context allocated locals. If // no contexts are allocated for this scope ContextLength returns 0. - int ContextLength(); + int ContextLength(bool qml_function = false); // Is this scope the scope of a named function expression? bool HasFunctionName(); @@ -3566,11 +3569,14 @@ class ScopeInfo : public FixedArray { // 3. The number of non-parameter variables allocated on the stack. // 4. The number of non-parameter and parameter variables allocated in the // context. + // 5. The number of non-parameter and parameter variables allocated in the + // QML context. (technically placeholder) #define FOR_EACH_NUMERIC_FIELD(V) \ V(Flags) \ V(ParameterCount) \ V(StackLocalCount) \ - V(ContextLocalCount) + V(ContextLocalCount) \ + V(QmlContextLocalCount) #define FIELD_ACCESSORS(name) \ void Set##name(int value) { \ @@ -3640,8 +3646,9 @@ class ScopeInfo : public FixedArray { class TypeField: public BitField<ScopeType, 0, 3> {}; class CallsEvalField: public BitField<bool, 3, 1> {}; class LanguageModeField: public BitField<LanguageMode, 4, 2> {}; - class FunctionVariableField: public BitField<FunctionVariableInfo, 6, 2> {}; - class FunctionVariableMode: public BitField<VariableMode, 8, 3> {}; + class QmlModeField: public BitField<bool, 6, 1> {}; + class FunctionVariableField: public BitField<FunctionVariableInfo, 7, 2> {}; + class FunctionVariableMode: public BitField<VariableMode, 9, 3> {}; // BitFields representing the encoded information for context locals in the // ContextLocalInfoEntries part. @@ -5756,6 +5763,9 @@ class SharedFunctionInfo: public HeapObject { // Indicates whether the language mode of this function is EXTENDED_MODE. inline bool is_extended_mode(); + // Indicates whether the function is a qml mode function. + DECL_BOOLEAN_ACCESSORS(qml_mode) + // False if the function definitely does not allocate an arguments object. DECL_BOOLEAN_ACCESSORS(uses_arguments) @@ -6015,6 +6025,7 @@ class SharedFunctionInfo: public HeapObject { kOptimizationDisabled = kCodeAgeShift + kCodeAgeSize, kStrictModeFunction, kExtendedModeFunction, + kQmlModeFunction, kUsesArguments, kHasDuplicateParameters, kNative, diff --git a/src/3rdparty/v8/src/parser.cc b/src/3rdparty/v8/src/parser.cc index 129bd95..da4685f 100644 --- a/src/3rdparty/v8/src/parser.cc +++ b/src/3rdparty/v8/src/parser.cc @@ -639,6 +639,9 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, FunctionState function_state(this, scope, isolate()); // Enters 'scope'. top_scope_->SetLanguageMode(info->language_mode()); + if (info->is_qml_mode()) { + scope->EnableQmlModeFlag(); + } ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16, zone()); bool ok = true; int beg_loc = scanner().location().beg_pos; @@ -745,6 +748,9 @@ FunctionLiteral* Parser::ParseLazy(Utf16CharacterStream* source, info()->is_extended_mode()); ASSERT(info()->language_mode() == shared_info->language_mode()); scope->SetLanguageMode(shared_info->language_mode()); + if (shared_info->qml_mode()) { + top_scope_->EnableQmlModeFlag(); + } FunctionLiteral::Type type = shared_info->is_expression() ? (shared_info->is_anonymous() ? FunctionLiteral::ANONYMOUS_EXPRESSION @@ -1782,6 +1788,25 @@ void Parser::Declare(Declaration* declaration, bool resolve, bool* ok) { // both access to the static and the dynamic context chain; the // runtime needs to provide both. if (resolve && var != NULL) { + if (declaration_scope->is_qml_mode()) { + Handle<GlobalObject> global = isolate_->global_object(); + +#ifdef ENABLE_DEBUGGER_SUPPORT + if (isolate_->debug()->IsLoaded() && isolate_->debug()->InDebugger()) { + // Get the context before the debugger was entered. + SaveContext *save = isolate_->save_context(); + while (save != NULL && *save->context() == *isolate_->debug()->debug_context()) + save = save->prev(); + + global = Handle<GlobalObject>(save->context()->global_object()); + } +#endif + + if (!global->HasProperty(*(proxy->name()))) { + var->set_is_qml_global(true); + } + } + proxy->BindTo(var); if (FLAG_harmony_modules) { @@ -2219,6 +2244,12 @@ Block* Parser::ParseVariableDeclarations( arguments->Add(value, zone()); value = NULL; // zap the value to avoid the unnecessary assignment + int qml_mode = 0; + if (top_scope_->is_qml_mode() + && !Isolate::Current()->global_object()->HasProperty(*name)) + qml_mode = 1; + arguments->Add(factory()->NewNumberLiteral(qml_mode), zone()); + // Construct the call to Runtime_InitializeConstGlobal // and add it to the initialization statement block. // Note that the function does different things depending on @@ -2233,6 +2264,12 @@ Block* Parser::ParseVariableDeclarations( LanguageMode language_mode = initialization_scope->language_mode(); arguments->Add(factory()->NewNumberLiteral(language_mode), zone()); + int qml_mode = 0; + if (top_scope_->is_qml_mode() + && !Isolate::Current()->global_object()->HasProperty(*name)) + qml_mode = 1; + arguments->Add(factory()->NewNumberLiteral(qml_mode), zone()); + // Be careful not to assign a value to the global variable if // we're in a with. The initialization value should not // necessarily be stored in the global object in that case, diff --git a/src/3rdparty/v8/src/prettyprinter.cc b/src/3rdparty/v8/src/prettyprinter.cc index 0d8dadc..16eb85a 100644 --- a/src/3rdparty/v8/src/prettyprinter.cc +++ b/src/3rdparty/v8/src/prettyprinter.cc @@ -672,6 +672,9 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info, EmbeddedVector<char, 256> buf; int pos = OS::SNPrintF(buf, "%s (mode = %s", info, Variable::Mode2String(var->mode())); + if (var->is_qml_global()) { + pos += OS::SNPrintF(buf + pos, ":QML"); + } OS::SNPrintF(buf + pos, ")"); PrintLiteralIndented(buf.start(), value, true); } diff --git a/src/3rdparty/v8/src/runtime.cc b/src/3rdparty/v8/src/runtime.cc index a0d8326..088c939 100644 --- a/src/3rdparty/v8/src/runtime.cc +++ b/src/3rdparty/v8/src/runtime.cc @@ -1357,19 +1357,24 @@ static Failure* ThrowRedeclarationError(Isolate* isolate, RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { ASSERT(args.length() == 3); HandleScope scope(isolate); - Handle<GlobalObject> global = Handle<GlobalObject>( - isolate->context()->global_object()); Handle<Context> context = args.at<Context>(0); CONVERT_ARG_HANDLE_CHECKED(FixedArray, pairs, 1); CONVERT_SMI_ARG_CHECKED(flags, 2); + Handle<JSObject> js_global = Handle<JSObject>(isolate->context()->global_object()); + Handle<JSObject> qml_global = Handle<JSObject>(isolate->context()->qml_global_object()); + // Traverse the name/value pairs and set the properties. int length = pairs->length(); - for (int i = 0; i < length; i += 2) { + for (int i = 0; i < length; i += 3) { HandleScope scope(isolate); Handle<String> name(String::cast(pairs->get(i))); Handle<Object> value(pairs->get(i + 1), isolate); + Handle<Object> is_qml_global(pairs->get(i + 2)); + ASSERT(is_qml_global->IsBoolean()); + + Handle<JSObject> global = is_qml_global->IsTrue() ? qml_global : js_global; // We have to declare a global const property. To capture we only // assign to it when evaluating the assignment for "const x = @@ -1569,20 +1574,26 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { NoHandleAllocation nha; // args[0] == name // args[1] == language_mode - // args[2] == value (optional) + // args[2] == qml_mode + // args[3] == value (optional) // Determine if we need to assign to the variable if it already // exists (based on the number of arguments). - RUNTIME_ASSERT(args.length() == 2 || args.length() == 3); - bool assign = args.length() == 3; + RUNTIME_ASSERT(args.length() == 3 || args.length() == 4); + bool assign = args.length() == 4; CONVERT_ARG_HANDLE_CHECKED(String, name, 0); - GlobalObject* global = isolate->context()->global_object(); RUNTIME_ASSERT(args[1]->IsSmi()); CONVERT_LANGUAGE_MODE_ARG(language_mode, 1); StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE) ? kNonStrictMode : kStrictMode; + RUNTIME_ASSERT(args[2]->IsSmi()); + int qml_mode = Smi::cast(args[2])->value(); + + JSObject* global = qml_mode ? isolate->context()->qml_global_object() + : isolate->context()->global_object(); + // According to ECMA-262, section 12.2, page 62, the property must // not be deletable. PropertyAttributes attributes = DONT_DELETE; @@ -1610,7 +1621,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { // Found an interceptor that's not read only. if (assign) { return raw_holder->SetProperty( - &lookup, *name, args[2], attributes, strict_mode_flag); + &lookup, *name, args[3], attributes, strict_mode_flag); } else { return isolate->heap()->undefined_value(); } @@ -1620,10 +1631,11 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { } // Reload global in case the loop above performed a GC. - global = isolate->context()->global_object(); + global = qml_mode ? isolate->context()->qml_global_object() + : isolate->context()->global_object(); if (assign) { return global->SetProperty( - *name, args[2], attributes, strict_mode_flag, JSReceiver::MAY_BE_STORE_FROM_KEYED, true); + *name, args[3], attributes, strict_mode_flag, JSReceiver::MAY_BE_STORE_FROM_KEYED, true); } return isolate->heap()->undefined_value(); } @@ -1633,12 +1645,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { // All constants are declared with an initial value. The name // of the constant is the first argument and the initial value // is the second. - RUNTIME_ASSERT(args.length() == 2); + RUNTIME_ASSERT(args.length() == 3); CONVERT_ARG_HANDLE_CHECKED(String, name, 0); Handle<Object> value = args.at<Object>(1); + RUNTIME_ASSERT(args[2]->IsSmi()); + int qml_mode = Smi::cast(args[2])->value(); + // Get the current global object from top. - GlobalObject* global = isolate->context()->global_object(); + JSObject* global = qml_mode ? isolate->context()->qml_global_object() + : isolate->context()->global_object(); // According to ECMA-262, section 12.2, page 62, the property must // not be deletable. Since it's a const, it must be READ_ONLY too. @@ -1662,7 +1678,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { // Restore global object from context (in case of GC) and continue // with setting the value. HandleScope handle_scope(isolate); - Handle<GlobalObject> global(isolate->context()->global_object()); + Handle<JSObject> global(qml_mode ? isolate->context()->qml_global_object() + : isolate->context()->global_object()); // BUG 1213575: Handle the case where we have to set a read-only // property through an interceptor and only do it if it's @@ -8420,7 +8437,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) { ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(JSFunction, function, 0); - int length = function->shared()->scope_info()->ContextLength(); + SharedFunctionInfo* shared = function->shared(); + // TODO: The QML mode should be checked in the ContextLength function. + int length = shared->scope_info()->ContextLength(shared->qml_mode()); Context* result; MaybeObject* maybe_result = isolate->heap()->AllocateFunctionContext(length, function); @@ -9116,7 +9135,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { // Compile source string in the native context. Handle<SharedFunctionInfo> shared = Compiler::CompileEval( - source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition); + source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition, false); if (shared.is_null()) return Failure::Exception(); Handle<JSFunction> fun = isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, @@ -9130,7 +9149,8 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<String> source, Handle<Object> receiver, LanguageMode language_mode, - int scope_position) { + int scope_position, + bool qml_mode) { Handle<Context> context = Handle<Context>(isolate->context()); Handle<Context> native_context = Handle<Context>(context->native_context()); @@ -9152,7 +9172,8 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<Context>(isolate->context()), context->IsNativeContext(), language_mode, - scope_position); + scope_position, + qml_mode); if (shared.is_null()) return MakePair(Failure::Exception(), NULL); Handle<JSFunction> compiled = isolate->factory()->NewFunctionFromSharedFunctionInfo( @@ -9162,7 +9183,7 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { - ASSERT(args.length() == 5); + ASSERT(args.length() == 6); HandleScope scope(isolate); Handle<Object> callee = args.at<Object>(0); @@ -9183,7 +9204,8 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { args.at<String>(1), args.at<Object>(2), language_mode, - args.smi_at(4)); + args.smi_at(4), + Smi::cast(args[5])->value()); } @@ -11749,6 +11771,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction())); Handle<ScopeInfo> scope_info(function->shared()->scope_info()); + bool qml_mode = function->shared()->qml_mode(); // Traverse the saved contexts chain to find the active context for the // selected frame. @@ -11830,7 +11853,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { context, context->IsNativeContext(), CLASSIC_MODE, - RelocInfo::kNoPosition); + RelocInfo::kNoPosition, + qml_mode); if (shared.is_null()) return Failure::Exception(); Handle<JSFunction> compiled_function = isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context); @@ -11840,7 +11864,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { Handle<Object> receiver(frame->receiver(), isolate); Handle<Object> evaluation_function = Execution::Call(compiled_function, receiver, 0, NULL, - &has_pending_exception); + &has_pending_exception, false, + Handle<Object>(function->context()->qml_global_object())); if (has_pending_exception) return Failure::Exception(); Handle<Object> arguments = GetArgumentsObject(isolate, @@ -11936,7 +11961,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) { context, is_global, CLASSIC_MODE, - RelocInfo::kNoPosition); + RelocInfo::kNoPosition, + false); if (shared.is_null()) return Failure::Exception(); Handle<JSFunction> compiled_function = Handle<JSFunction>( diff --git a/src/3rdparty/v8/src/runtime.h b/src/3rdparty/v8/src/runtime.h index f63844c..9c3e541 100644 --- a/src/3rdparty/v8/src/runtime.h +++ b/src/3rdparty/v8/src/runtime.h @@ -261,7 +261,7 @@ namespace internal { \ /* Eval */ \ F(GlobalReceiver, 1, 1) \ - F(ResolvePossiblyDirectEval, 5, 2) \ + F(ResolvePossiblyDirectEval, 6, 2) \ \ F(SetProperty, -1 /* 4 or 5 */, 1) \ F(DefineOrRedefineDataProperty, 4, 1) \ @@ -358,8 +358,8 @@ namespace internal { /* Declarations and initialization */ \ F(DeclareGlobals, 3, 1) \ F(DeclareContextSlot, 4, 1) \ - F(InitializeVarGlobal, -1 /* 2 or 3 */, 1) \ - F(InitializeConstGlobal, 2, 1) \ + F(InitializeVarGlobal, -1 /* 3 or 4 */, 1) \ + F(InitializeConstGlobal, 3, 1) \ F(InitializeConstContextSlot, 3, 1) \ F(OptimizeObjectForAddingMultipleProperties, 2, 1) \ \ diff --git a/src/3rdparty/v8/src/scopeinfo.cc b/src/3rdparty/v8/src/scopeinfo.cc index 02b4323..66e2013 100644 --- a/src/3rdparty/v8/src/scopeinfo.cc +++ b/src/3rdparty/v8/src/scopeinfo.cc @@ -80,6 +80,7 @@ Handle<ScopeInfo> ScopeInfo::Create(Scope* scope, Zone* zone) { int flags = TypeField::encode(scope->type()) | CallsEvalField::encode(scope->calls_eval()) | LanguageModeField::encode(scope->language_mode()) | + QmlModeField::encode(scope->is_qml_mode()) | FunctionVariableField::encode(function_name_info) | FunctionVariableMode::encode(function_variable_mode); scope_info->SetFlags(flags); @@ -170,6 +171,11 @@ LanguageMode ScopeInfo::language_mode() { } +bool ScopeInfo::IsQmlMode() { + return length() > 0 && QmlModeField::decode(Flags()); +} + + int ScopeInfo::LocalCount() { return StackLocalCount() + ContextLocalCount(); } @@ -185,7 +191,7 @@ int ScopeInfo::StackSlotCount() { } -int ScopeInfo::ContextLength() { +int ScopeInfo::ContextLength(bool qml_function) { if (length() > 0) { int context_locals = ContextLocalCount(); bool function_name_context_slot = @@ -195,7 +201,8 @@ int ScopeInfo::ContextLength() { Type() == WITH_SCOPE || (Type() == FUNCTION_SCOPE && CallsEval()) || Type() == MODULE_SCOPE; - if (has_context) { + // TODO: The QML mode should be checked in the has_context expression. + if (has_context || qml_function) { return Context::MIN_CONTEXT_SLOTS + context_locals + (function_name_context_slot ? 1 : 0); } diff --git a/src/3rdparty/v8/src/scopes.cc b/src/3rdparty/v8/src/scopes.cc index c961257..d2a919a 100644 --- a/src/3rdparty/v8/src/scopes.cc +++ b/src/3rdparty/v8/src/scopes.cc @@ -37,6 +37,8 @@ #include "allocation-inl.h" +#include "debug.h" + namespace v8 { namespace internal { @@ -191,6 +193,8 @@ void Scope::SetDefaults(ScopeType type, // Inherit the strict mode from the parent scope. language_mode_ = (outer_scope != NULL) ? outer_scope->language_mode_ : CLASSIC_MODE; + qml_mode_flag_ = (outer_scope != NULL) + ? outer_scope->qml_mode_flag_ : kNonQmlMode; outer_scope_calls_non_strict_eval_ = false; inner_scope_calls_eval_ = false; force_eager_compilation_ = false; @@ -1029,6 +1033,24 @@ bool Scope::ResolveVariable(CompilationInfo* info, switch (binding_kind) { case BOUND: // We found a variable binding. + if (is_qml_mode()) { + Handle<GlobalObject> global = isolate_->global_object(); + +#ifdef ENABLE_DEBUGGER_SUPPORT + if (isolate_->debug()->IsLoaded() && isolate_->debug()->InDebugger()) { + // Get the context before the debugger was entered. + SaveContext *save = isolate_->save_context(); + while (save != NULL && *save->context() == *isolate_->debug()->debug_context()) + save = save->prev(); + + global = Handle<GlobalObject>(save->context()->global_object()); + } +#endif + + if (!global->HasProperty(*(proxy->name()))) { + var->set_is_qml_global(true); + } + } break; case BOUND_EVAL_SHADOWED: @@ -1038,6 +1060,25 @@ bool Scope::ResolveVariable(CompilationInfo* info, // debugger to evaluate arbitrary expressions at a break point). if (var->IsGlobalObjectProperty()) { var = NonLocal(proxy->name(), DYNAMIC_GLOBAL); + + if (is_qml_mode()) { + Handle<GlobalObject> global = isolate_->global_object(); + +#ifdef ENABLE_DEBUGGER_SUPPORT + if (isolate_->debug()->IsLoaded() && isolate_->debug()->InDebugger()) { + // Get the context before the debugger was entered. + SaveContext *save = isolate_->save_context(); + while (save != NULL && *save->context() == *isolate_->debug()->debug_context()) + save = save->prev(); + + global = Handle<GlobalObject>(save->context()->global_object()); + } +#endif + + if (!global->HasProperty(*(proxy->name()))) { + var->set_is_qml_global(true); + } + } } else if (var->is_dynamic()) { var = NonLocal(proxy->name(), DYNAMIC); } else { @@ -1050,12 +1091,52 @@ bool Scope::ResolveVariable(CompilationInfo* info, case UNBOUND: // No binding has been found. Declare a variable on the global object. var = info->global_scope()->DeclareDynamicGlobal(proxy->name()); + + if (is_qml_mode()) { + Handle<GlobalObject> global = isolate_->global_object(); + +#ifdef ENABLE_DEBUGGER_SUPPORT + if (isolate_->debug()->IsLoaded() && isolate_->debug()->InDebugger()) { + // Get the context before the debugger was entered. + SaveContext *save = isolate_->save_context(); + while (save != NULL && *save->context() == *isolate_->debug()->debug_context()) + save = save->prev(); + + global = Handle<GlobalObject>(save->context()->global_object()); + } +#endif + + if (!global->HasProperty(*(proxy->name()))) { + var->set_is_qml_global(true); + } + } + break; case UNBOUND_EVAL_SHADOWED: // No binding has been found. But some scope makes a // non-strict 'eval' call. var = NonLocal(proxy->name(), DYNAMIC_GLOBAL); + + if (is_qml_mode()) { + Handle<GlobalObject> global = isolate_->global_object(); + +#ifdef ENABLE_DEBUGGER_SUPPORT + if (isolate_->debug()->IsLoaded() && isolate_->debug()->InDebugger()) { + // Get the context before the debugger was entered. + SaveContext *save = isolate_->save_context(); + while (save != NULL && *save->context() == *isolate_->debug()->debug_context()) + save = save->prev(); + + global = Handle<GlobalObject>(save->context()->global_object()); + } +#endif + + if (!global->HasProperty(*(proxy->name()))) { + var->set_is_qml_global(true); + } + } + break; case DYNAMIC_LOOKUP: diff --git a/src/3rdparty/v8/src/scopes.h b/src/3rdparty/v8/src/scopes.h index b9d151c..e9425f0 100644 --- a/src/3rdparty/v8/src/scopes.h +++ b/src/3rdparty/v8/src/scopes.h @@ -237,6 +237,11 @@ class Scope: public ZoneObject { language_mode_ = language_mode; } + // Enable qml mode for this scope + void EnableQmlModeFlag() { + qml_mode_flag_ = kQmlMode; + } + // Position in the source where this scope begins and ends. // // * For the scope of a with statement @@ -292,6 +297,7 @@ class Scope: public ZoneObject { bool is_strict_or_extended_eval_scope() const { return is_eval_scope() && !is_classic_mode(); } + bool is_qml_mode() const { return qml_mode_flag() == kQmlMode; } // Information about which scopes calls eval. bool calls_eval() const { return scope_calls_eval_; } @@ -316,6 +322,9 @@ class Scope: public ZoneObject { // The language mode of this scope. LanguageMode language_mode() const { return language_mode_; } + // The strict mode of this scope. + QmlModeFlag qml_mode_flag() const { return qml_mode_flag_; } + // The variable corresponding the 'this' value. Variable* receiver() { return receiver_; } @@ -474,6 +483,8 @@ class Scope: public ZoneObject { bool scope_calls_eval_; // The language mode of this scope. LanguageMode language_mode_; + // This scope is a qml mode scope. + QmlModeFlag qml_mode_flag_; // Source positions. int start_position_; int end_position_; diff --git a/src/3rdparty/v8/src/stub-cache.cc b/src/3rdparty/v8/src/stub-cache.cc index 5eb0cba..3885462 100644 --- a/src/3rdparty/v8/src/stub-cache.cc +++ b/src/3rdparty/v8/src/stub-cache.cc @@ -809,7 +809,8 @@ Handle<Code> StubCache::ComputeCallPreMonomorphic( Handle<Code> StubCache::ComputeCallNormal(int argc, Code::Kind kind, - Code::ExtraICState extra_state) { + Code::ExtraICState extra_state, + bool has_qml_global_receiver) { Code::Flags flags = Code::ComputeFlags(kind, MONOMORPHIC, extra_state, Code::NORMAL, argc); Handle<UnseededNumberDictionary> cache = @@ -818,7 +819,7 @@ Handle<Code> StubCache::ComputeCallNormal(int argc, if (entry != -1) return Handle<Code>(Code::cast(cache->ValueAt(entry))); StubCompiler compiler(isolate_); - Handle<Code> code = compiler.CompileCallNormal(flags); + Handle<Code> code = compiler.CompileCallNormal(flags, has_qml_global_receiver); FillCache(isolate_, code); return code; } @@ -1234,13 +1235,15 @@ Handle<Code> StubCompiler::CompileCallPreMonomorphic(Code::Flags flags) { } -Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags) { +Handle<Code> StubCompiler::CompileCallNormal(Code::Flags flags, bool has_qml_global_receiver) { int argc = Code::ExtractArgumentsCountFromFlags(flags); Code::Kind kind = Code::ExtractKindFromFlags(flags); if (kind == Code::CALL_IC) { - // Call normal is always with a explict receiver. + // Call normal is always with a explict receiver, + // or with an implicit qml global receiver. ASSERT(!CallIC::Contextual::decode( - Code::ExtractExtraICStateFromFlags(flags))); + Code::ExtractExtraICStateFromFlags(flags)) || + has_qml_global_receiver); CallIC::GenerateNormal(masm(), argc); } else { KeyedCallIC::GenerateNormal(masm(), argc); diff --git a/src/3rdparty/v8/src/stub-cache.h b/src/3rdparty/v8/src/stub-cache.h index 005c537..ec9274b 100644 --- a/src/3rdparty/v8/src/stub-cache.h +++ b/src/3rdparty/v8/src/stub-cache.h @@ -231,7 +231,8 @@ class StubCache { Handle<Code> ComputeCallNormal(int argc, Code::Kind kind, - Code::ExtraICState state); + Code::ExtraICState state, + bool has_qml_global_receiver); Handle<Code> ComputeCallArguments(int argc, Code::Kind kind); @@ -423,7 +424,7 @@ class StubCompiler BASE_EMBEDDED { // is extracted from the code flags. Handle<Code> CompileCallInitialize(Code::Flags flags); Handle<Code> CompileCallPreMonomorphic(Code::Flags flags); - Handle<Code> CompileCallNormal(Code::Flags flags); + Handle<Code> CompileCallNormal(Code::Flags flags, bool has_qml_global_receiver); Handle<Code> CompileCallMegamorphic(Code::Flags flags); Handle<Code> CompileCallArguments(Code::Flags flags); Handle<Code> CompileCallMiss(Code::Flags flags); diff --git a/src/3rdparty/v8/src/variables.cc b/src/3rdparty/v8/src/variables.cc index 0416f3a..3e735d6 100644 --- a/src/3rdparty/v8/src/variables.cc +++ b/src/3rdparty/v8/src/variables.cc @@ -73,7 +73,8 @@ Variable::Variable(Scope* scope, force_context_allocation_(false), is_used_(false), initialization_flag_(initialization_flag), - interface_(interface) { + interface_(interface), + is_qml_global_(false) { // Names must be canonicalized for fast equality checks. ASSERT(name->IsSymbol()); // Var declared variables never need initialization. diff --git a/src/3rdparty/v8/src/variables.h b/src/3rdparty/v8/src/variables.h index ba26b80..d4e851b 100644 --- a/src/3rdparty/v8/src/variables.h +++ b/src/3rdparty/v8/src/variables.h @@ -157,6 +157,9 @@ class Variable: public ZoneObject { static int CompareIndex(Variable* const* v, Variable* const* w); + bool is_qml_global() const { return is_qml_global_; } + void set_is_qml_global(bool is_qml_global) { is_qml_global_ = is_qml_global; } + private: Scope* scope_; Handle<String> name_; @@ -182,6 +185,9 @@ class Variable: public ZoneObject { // Module type info. Interface* interface_; + + // QML info + bool is_qml_global_; }; diff --git a/src/3rdparty/v8/src/x64/code-stubs-x64.cc b/src/3rdparty/v8/src/x64/code-stubs-x64.cc index a8e52e9..8543094 100644 --- a/src/3rdparty/v8/src/x64/code-stubs-x64.cc +++ b/src/3rdparty/v8/src/x64/code-stubs-x64.cc @@ -220,6 +220,10 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)), rbx); + // Copy the qmlglobal object from the previous context. + __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::QML_GLOBAL_OBJECT_INDEX))); + __ movq(Operand(rax, Context::SlotOffset(Context::QML_GLOBAL_OBJECT_INDEX)), rbx); + // Initialize the rest of the slots to undefined. __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { @@ -284,6 +288,10 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) { __ movq(rbx, ContextOperand(rsi, Context::GLOBAL_OBJECT_INDEX)); __ movq(ContextOperand(rax, Context::GLOBAL_OBJECT_INDEX), rbx); + // Copy the qmlglobal object from the previous context. + __ movq(rbx, ContextOperand(rsi, Context::QML_GLOBAL_OBJECT_INDEX)); + __ movq(ContextOperand(rax, Context::QML_GLOBAL_OBJECT_INDEX), rbx); + // Initialize the rest of the slots to the hole value. __ LoadRoot(rbx, Heap::kTheHoleValueRootIndex); for (int i = 0; i < slots_; i++) { diff --git a/src/3rdparty/v8/src/x64/full-codegen-x64.cc b/src/3rdparty/v8/src/x64/full-codegen-x64.cc index a198739..a71c9b1 100644 --- a/src/3rdparty/v8/src/x64/full-codegen-x64.cc +++ b/src/3rdparty/v8/src/x64/full-codegen-x64.cc @@ -177,7 +177,8 @@ void FullCodeGenerator::Generate() { // Possibly allocate a local context. int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; - if (heap_slots > 0) { + if (heap_slots > 0 || + (scope()->is_qml_mode() && scope()->is_global_scope())) { Comment cmnt(masm_, "[ Allocate context"); // Argument to NewContext is the function, which is still in rdi. __ push(rdi); @@ -185,7 +186,7 @@ void FullCodeGenerator::Generate() { __ Push(info->scope()->GetScopeInfo()); __ CallRuntime(Runtime::kNewGlobalContext, 2); } else if (heap_slots <= FastNewContextStub::kMaximumSlots) { - FastNewContextStub stub(heap_slots); + FastNewContextStub stub((heap_slots < 0) ? 0 : heap_slots); __ CallStub(&stub); } else { __ CallRuntime(Runtime::kNewFunctionContext, 1); @@ -793,6 +794,7 @@ void FullCodeGenerator::VisitVariableDeclaration( ? isolate()->factory()->the_hole_value() : isolate()->factory()->undefined_value(), zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); break; case Variable::PARAMETER: @@ -852,6 +854,7 @@ void FullCodeGenerator::VisitFunctionDeclaration( // Check for stack-overflow exception. if (function.is_null()) return SetStackOverflow(); globals_->Add(function, zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); break; } @@ -905,6 +908,7 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { Comment cmnt(masm_, "[ ModuleDeclaration"); globals_->Add(variable->name(), zone()); globals_->Add(instance, zone()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global()), zone()); Visit(declaration->module()); break; } @@ -1317,7 +1321,7 @@ void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var, // All extension objects were empty and it is safe to use a global // load IC call. - __ movq(rax, GlobalObjectOperand()); + __ movq(rax, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); __ Move(rcx, var->name()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) @@ -1402,7 +1406,7 @@ void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) { // Use inline caching. Variable name is passed in rcx and the global // object on the stack. __ Move(rcx, var->name()); - __ movq(rax, GlobalObjectOperand()); + __ movq(rax, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); context()->Plug(rax); @@ -2031,7 +2035,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, if (var->IsUnallocated()) { // Global var, const, or let. __ Move(rcx, var->name()); - __ movq(rdx, GlobalObjectOperand()); + __ movq(rdx, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); Handle<Code> ic = is_classic_mode() ? isolate()->builtins()->StoreIC_Initialize() : isolate()->builtins()->StoreIC_Initialize_Strict(); @@ -2287,8 +2291,11 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) { // Push the start position of the scope the calls resides in. __ Push(Smi::FromInt(scope()->start_position())); + // Push the qml mode flag + __ Push(Smi::FromInt(is_qml_mode())); + // Do the runtime call. - __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5); + __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6); } @@ -2341,7 +2348,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { } else if (proxy != NULL && proxy->var()->IsUnallocated()) { // Call to a global variable. Push global object as receiver for the // call IC lookup. - __ push(GlobalObjectOperand()); + __ push(proxy->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT); } else if (proxy != NULL && proxy->var()->IsLookupSlot()) { // Call to a lookup slot (dynamically introduced variable). @@ -3818,7 +3825,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { // but "delete this" is allowed. ASSERT(language_mode() == CLASSIC_MODE || var->is_this()); if (var->IsUnallocated()) { - __ push(GlobalObjectOperand()); + __ push(var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); __ Push(var->name()); __ Push(Smi::FromInt(kNonStrictMode)); __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); @@ -4141,7 +4148,7 @@ void FullCodeGenerator::VisitForTypeofValue(Expression* expr) { if (proxy != NULL && proxy->var()->IsUnallocated()) { Comment cmnt(masm_, "Global variable"); __ Move(rcx, proxy->name()); - __ movq(rax, GlobalObjectOperand()); + __ movq(rax, proxy->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); // Use a regular load, not a contextual load, to avoid a reference // error. diff --git a/src/3rdparty/v8/src/x64/lithium-codegen-x64.cc b/src/3rdparty/v8/src/x64/lithium-codegen-x64.cc index 4596aca..a948ccc 100644 --- a/src/3rdparty/v8/src/x64/lithium-codegen-x64.cc +++ b/src/3rdparty/v8/src/x64/lithium-codegen-x64.cc @@ -181,12 +181,13 @@ bool LCodeGen::GeneratePrologue() { // Possibly allocate a local context. int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; - if (heap_slots > 0) { + if (heap_slots > 0 || + (scope()->is_qml_mode() && scope()->is_global_scope())) { Comment(";;; Allocate local context"); // Argument to NewContext is the function, which is still in rdi. __ push(rdi); if (heap_slots <= FastNewContextStub::kMaximumSlots) { - FastNewContextStub stub(heap_slots); + FastNewContextStub stub((heap_slots < 0)?0:heap_slots); __ CallStub(&stub); } else { __ CallRuntime(Runtime::kNewFunctionContext, 1); @@ -2988,7 +2989,7 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { void LCodeGen::DoGlobalObject(LGlobalObject* instr) { Register result = ToRegister(instr->result()); - __ movq(result, GlobalObjectOperand()); + __ movq(result, instr->qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); } diff --git a/src/3rdparty/v8/src/x64/lithium-x64.cc b/src/3rdparty/v8/src/x64/lithium-x64.cc index c6004e5..3985dc0 100644 --- a/src/3rdparty/v8/src/x64/lithium-x64.cc +++ b/src/3rdparty/v8/src/x64/lithium-x64.cc @@ -999,7 +999,7 @@ LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) { LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { - return DefineAsRegister(new(zone()) LGlobalObject); + return DefineAsRegister(new(zone()) LGlobalObject(instr->qml_global())); } @@ -1069,7 +1069,7 @@ LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) { LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) { argument_count_ -= instr->argument_count(); - return MarkAsCall(DefineFixed(new(zone()) LCallGlobal, rax), instr); + return MarkAsCall(DefineFixed(new(zone()) LCallGlobal(instr->qml_global()), rax), instr); } diff --git a/src/3rdparty/v8/src/x64/lithium-x64.h b/src/3rdparty/v8/src/x64/lithium-x64.h index 5439028..a437a2b 100644 --- a/src/3rdparty/v8/src/x64/lithium-x64.h +++ b/src/3rdparty/v8/src/x64/lithium-x64.h @@ -1546,7 +1546,13 @@ class LDeclareGlobals: public LTemplateInstruction<0, 0, 0> { class LGlobalObject: public LTemplateInstruction<1, 0, 0> { public: + explicit LGlobalObject(bool qml_global) : qml_global_(qml_global) {} + DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") + + bool qml_global() { return qml_global_; } + private: + bool qml_global_; }; @@ -1640,10 +1646,16 @@ class LCallGlobal: public LTemplateInstruction<1, 0, 0> { DECLARE_CONCRETE_INSTRUCTION(CallGlobal, "call-global") DECLARE_HYDROGEN_ACCESSOR(CallGlobal) + explicit LCallGlobal(bool qml_global) : qml_global_(qml_global) {} + virtual void PrintDataTo(StringStream* stream); Handle<String> name() const {return hydrogen()->name(); } int arity() const { return hydrogen()->argument_count() - 1; } + + bool qml_global() { return qml_global_; } + private: + bool qml_global_; }; diff --git a/src/3rdparty/v8/src/x64/macro-assembler-x64.h b/src/3rdparty/v8/src/x64/macro-assembler-x64.h index cc057ac..fdddc13 100644 --- a/src/3rdparty/v8/src/x64/macro-assembler-x64.h +++ b/src/3rdparty/v8/src/x64/macro-assembler-x64.h @@ -1467,6 +1467,11 @@ inline Operand GlobalObjectOperand() { } +static inline Operand QmlGlobalObjectOperand() { + return ContextOperand(rsi, Context::QML_GLOBAL_OBJECT_INDEX); +} + + // Provides access to exit frame stack space (not GCed). inline Operand StackSpaceOperand(int index) { #ifdef _WIN64 diff --git a/src/3rdparty/v8/test/cctest/test-api.cc b/src/3rdparty/v8/test/cctest/test-api.cc index 41eb68f..f7325df 100644 --- a/src/3rdparty/v8/test/cctest/test-api.cc +++ b/src/3rdparty/v8/test/cctest/test-api.cc @@ -15155,6 +15155,7 @@ TEST(Regress528) { v8::Persistent<Context> context; v8::Persistent<Context> other_context; int gc_count; + bool snapshot_enabled = i::Snapshot::IsEnabled(); // Create a context used to keep the code from aging in the compilation // cache. @@ -15180,10 +15181,10 @@ TEST(Regress528) { CompileRun(source_simple); other_context->Exit(); HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); - if (GetGlobalObjectsCount() == 1) break; + if (GetGlobalObjectsCount() == (snapshot_enabled ? 2 : 1)) break; } CHECK_GE(2, gc_count); - CHECK_EQ(1, GetGlobalObjectsCount()); + CHECK_EQ((snapshot_enabled ? 2 : 1), GetGlobalObjectsCount()); // Eval in a function creates reference from the compilation cache to the // global object. @@ -15203,10 +15204,10 @@ TEST(Regress528) { CompileRun(source_eval); other_context->Exit(); HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); - if (GetGlobalObjectsCount() == 1) break; + if (GetGlobalObjectsCount() == (snapshot_enabled ? 2 : 1)) break; } CHECK_GE(2, gc_count); - CHECK_EQ(1, GetGlobalObjectsCount()); + CHECK_EQ((snapshot_enabled ? 2 : 1), GetGlobalObjectsCount()); // Looking up the line number for an exception creates reference from the // compilation cache to the global object. @@ -15231,10 +15232,10 @@ TEST(Regress528) { CompileRun(source_exception); other_context->Exit(); HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); - if (GetGlobalObjectsCount() == 1) break; + if (GetGlobalObjectsCount() == (snapshot_enabled ? 2 : 1)) break; } CHECK_GE(2, gc_count); - CHECK_EQ(1, GetGlobalObjectsCount()); + CHECK_EQ((snapshot_enabled ? 2 : 1), GetGlobalObjectsCount()); other_context.Dispose(); v8::V8::ContextDisposedNotification(); diff --git a/src/3rdparty/v8/test/cctest/test-heap-profiler.cc b/src/3rdparty/v8/test/cctest/test-heap-profiler.cc index 5235971..2a60785 100644 --- a/src/3rdparty/v8/test/cctest/test-heap-profiler.cc +++ b/src/3rdparty/v8/test/cctest/test-heap-profiler.cc @@ -66,9 +66,11 @@ class NamedEntriesDetector { static const v8::HeapGraphNode* GetGlobalObject( const v8::HeapSnapshot* snapshot) { - CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount()); + bool snapshot_enabled = i::Snapshot::IsEnabled(); + + CHECK_EQ((snapshot_enabled ? 3 : 2), snapshot->GetRoot()->GetChildrenCount()); const v8::HeapGraphNode* global_obj = - snapshot->GetRoot()->GetChild(0)->GetToNode(); + snapshot->GetRoot()->GetChild(snapshot_enabled ? 1 : 0)->GetToNode(); CHECK_EQ(0, strncmp("Object", const_cast<i::HeapEntry*>( reinterpret_cast<const i::HeapEntry*>(global_obj))->name(), 6)); return global_obj; @@ -601,14 +603,28 @@ TEST(HeapSnapshotJSONSerialization) { " return null;\n" "}\n"); // Get the string index using the path: <root> -> <global>.b.x.s - v8::Local<v8::Value> string_obj_pos_val = CompileRun( - "GetChildPosByProperty(\n" - " GetChildPosByProperty(\n" - " GetChildPosByProperty(" - " parsed.edges[edge_to_node_offset]," - " \"b\", property_type),\n" - " \"x\", property_type)," - " \"s\", property_type)"); + v8::Local<v8::Value> string_obj_pos_val; + if (i::Snapshot::IsEnabled()) { + // TODO(pvarga): Check shortcut_type issue at b when QML global object is used. + string_obj_pos_val = CompileRun( + "GetChildPosByProperty(\n" + " GetChildPosByProperty(\n" + " GetChildPosByProperty(" + " parsed.edges[edge_to_node_offset" + " + edge_fields_count]," + " \"b\", property_type),\n" + " \"x\", property_type)," + " \"s\", property_type)"); + } else { + string_obj_pos_val = CompileRun( + "GetChildPosByProperty(\n" + " GetChildPosByProperty(\n" + " GetChildPosByProperty(" + " parsed.edges[edge_to_node_offset]," + " \"b\", property_type),\n" + " \"x\", property_type)," + " \"s\", property_type)"); + } CHECK(!string_obj_pos_val.IsEmpty()); int string_obj_pos = static_cast<int>(string_obj_pos_val->ToNumber()->Value()); @@ -1571,6 +1587,8 @@ TEST(NoDebugObjectInSnapshot) { const v8::HeapGraphNode* root = snapshot->GetRoot(); int globals_count = 0; for (int i = 0; i < root->GetChildrenCount(); ++i) { + // QML global object should be skipped here when snapshot is enabled. + if (i::Snapshot::IsEnabled() && i % 2 == 0) continue; const v8::HeapGraphEdge* edge = root->GetChild(i); if (edge->GetType() == v8::HeapGraphEdge::kShortcut) { ++globals_count; diff --git a/src/3rdparty/v8/test/cctest/test-heap.cc b/src/3rdparty/v8/test/cctest/test-heap.cc index 2bb3af6..0d72ff7 100644 --- a/src/3rdparty/v8/test/cctest/test-heap.cc +++ b/src/3rdparty/v8/test/cctest/test-heap.cc @@ -11,6 +11,7 @@ #include "global-handles.h" #include "stub-cache.h" #include "cctest.h" +#include "snapshot.h" using namespace v8::internal; @@ -1577,13 +1578,14 @@ static int NumberOfGlobalObjects() { // optimized code. TEST(LeakNativeContextViaMap) { i::FLAG_allow_natives_syntax = true; + bool snapshot_enabled = i::Snapshot::IsEnabled(); v8::HandleScope outer_scope; v8::Persistent<v8::Context> ctx1 = v8::Context::New(); v8::Persistent<v8::Context> ctx2 = v8::Context::New(); ctx1->Enter(); HEAP->CollectAllAvailableGarbage(); - CHECK_EQ(4, NumberOfGlobalObjects()); + CHECK_EQ((snapshot_enabled ? 6 : 4), NumberOfGlobalObjects()); { v8::HandleScope inner_scope; @@ -1604,7 +1606,7 @@ TEST(LeakNativeContextViaMap) { v8::V8::ContextDisposedNotification(); } HEAP->CollectAllAvailableGarbage(); - CHECK_EQ(2, NumberOfGlobalObjects()); + CHECK_EQ((snapshot_enabled ? 3 : 2), NumberOfGlobalObjects()); ctx2.Dispose(); HEAP->CollectAllAvailableGarbage(); CHECK_EQ(0, NumberOfGlobalObjects()); @@ -1615,13 +1617,14 @@ TEST(LeakNativeContextViaMap) { // optimized code. TEST(LeakNativeContextViaFunction) { i::FLAG_allow_natives_syntax = true; + bool snapshot_enabled = i::Snapshot::IsEnabled(); v8::HandleScope outer_scope; v8::Persistent<v8::Context> ctx1 = v8::Context::New(); v8::Persistent<v8::Context> ctx2 = v8::Context::New(); ctx1->Enter(); HEAP->CollectAllAvailableGarbage(); - CHECK_EQ(4, NumberOfGlobalObjects()); + CHECK_EQ((snapshot_enabled ? 6 : 4), NumberOfGlobalObjects()); { v8::HandleScope inner_scope; @@ -1642,7 +1645,7 @@ TEST(LeakNativeContextViaFunction) { v8::V8::ContextDisposedNotification(); } HEAP->CollectAllAvailableGarbage(); - CHECK_EQ(2, NumberOfGlobalObjects()); + CHECK_EQ((snapshot_enabled ? 3 : 2), NumberOfGlobalObjects()); ctx2.Dispose(); HEAP->CollectAllAvailableGarbage(); CHECK_EQ(0, NumberOfGlobalObjects()); @@ -1651,13 +1654,14 @@ TEST(LeakNativeContextViaFunction) { TEST(LeakNativeContextViaMapKeyed) { i::FLAG_allow_natives_syntax = true; + bool snapshot_enabled = i::Snapshot::IsEnabled(); v8::HandleScope outer_scope; v8::Persistent<v8::Context> ctx1 = v8::Context::New(); v8::Persistent<v8::Context> ctx2 = v8::Context::New(); ctx1->Enter(); HEAP->CollectAllAvailableGarbage(); - CHECK_EQ(4, NumberOfGlobalObjects()); + CHECK_EQ((snapshot_enabled ? 6 : 4), NumberOfGlobalObjects()); { v8::HandleScope inner_scope; @@ -1678,7 +1682,7 @@ TEST(LeakNativeContextViaMapKeyed) { v8::V8::ContextDisposedNotification(); } HEAP->CollectAllAvailableGarbage(); - CHECK_EQ(2, NumberOfGlobalObjects()); + CHECK_EQ((snapshot_enabled ? 3 : 2), NumberOfGlobalObjects()); ctx2.Dispose(); HEAP->CollectAllAvailableGarbage(); CHECK_EQ(0, NumberOfGlobalObjects()); @@ -1687,13 +1691,14 @@ TEST(LeakNativeContextViaMapKeyed) { TEST(LeakNativeContextViaMapProto) { i::FLAG_allow_natives_syntax = true; + bool snapshot_enabled = i::Snapshot::IsEnabled(); v8::HandleScope outer_scope; v8::Persistent<v8::Context> ctx1 = v8::Context::New(); v8::Persistent<v8::Context> ctx2 = v8::Context::New(); ctx1->Enter(); HEAP->CollectAllAvailableGarbage(); - CHECK_EQ(4, NumberOfGlobalObjects()); + CHECK_EQ((snapshot_enabled ? 6 : 4), NumberOfGlobalObjects()); { v8::HandleScope inner_scope; @@ -1718,7 +1723,7 @@ TEST(LeakNativeContextViaMapProto) { v8::V8::ContextDisposedNotification(); } HEAP->CollectAllAvailableGarbage(); - CHECK_EQ(2, NumberOfGlobalObjects()); + CHECK_EQ((snapshot_enabled ? 3 : 2), NumberOfGlobalObjects()); ctx2.Dispose(); HEAP->CollectAllAvailableGarbage(); CHECK_EQ(0, NumberOfGlobalObjects()); |