diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-10-27 13:34:16 +0100 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-06-13 09:56:45 +0200 |
commit | 2df5be48c08803b6bafafe9c69959a4076022293 (patch) | |
tree | de9bd746c683190d5bee0d35e56420bee79589e0 /src | |
parent | ccad1b6e4ca295861ff50b8e84560dd9769930d1 (diff) | |
download | qtjsbackend-2df5be48c08803b6bafafe9c69959a4076022293.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: I86851683200d02208379744c887dfebc010a7ccc
Reviewed-by: Kent Hansen <kent.hansen@nokia.com>
Diffstat (limited to 'src')
60 files changed, 634 insertions, 153 deletions
diff --git a/src/3rdparty/v8/include/v8.h b/src/3rdparty/v8/include/v8.h index 5cc8e6f..7e614d0 100644 --- a/src/3rdparty/v8/include/v8.h +++ b/src/3rdparty/v8/include/v8.h @@ -590,6 +590,11 @@ class ScriptOrigin { */ class V8EXPORT Script { public: + enum CompileFlags { + Default = 0x00, + QmlMode = 0x01 + }; + /** * Compiles the specified script (context-independent). * @@ -608,7 +613,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 @@ -621,7 +627,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). @@ -642,7 +649,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 @@ -659,7 +667,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 @@ -669,6 +678,7 @@ class V8EXPORT Script { * compiled. */ Local<Value> Run(); + Local<Value> Run(Handle<Object> qml); /** * Returns the script id value. @@ -3608,6 +3618,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 2de7bb8..bdf2e67 100644 --- a/src/3rdparty/v8/src/api.cc +++ b/src/3rdparty/v8/src/api.cc @@ -1543,7 +1543,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"); @@ -1584,7 +1585,8 @@ Local<Script> Script::New(v8::Handle<String> source, NULL, pre_data_impl, Utils::OpenHandle(*script_data), - 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; @@ -1595,21 +1597,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); @@ -1625,13 +1629,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"); @@ -1650,10 +1659,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); 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; } @@ -4588,6 +4598,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()->IsUndefined()) { + i::Handle<i::Object> qmlglobal(context->qml_global()); + 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 ad2ab7e..d06faaa 100644 --- a/src/3rdparty/v8/src/arm/code-stubs-arm.cc +++ b/src/3rdparty/v8/src/arm/code-stubs-arm.cc @@ -169,6 +169,10 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { __ str(r1, MemOperand(r0, Context::SlotOffset(Context::EXTENSION_INDEX))); __ str(r2, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_INDEX))); + // Copy the qml global object from the surrounding context. + __ ldr(r1, MemOperand(cp, Context::SlotOffset(Context::QML_GLOBAL_INDEX))); + __ str(r1, MemOperand(r0, Context::SlotOffset(Context::QML_GLOBAL_INDEX))); + // Initialize the rest of the slots to undefined. __ LoadRoot(r1, Heap::kUndefinedValueRootIndex); for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { @@ -233,6 +237,10 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) { __ str(r1, ContextOperand(r0, Context::EXTENSION_INDEX)); __ str(r2, ContextOperand(r0, Context::GLOBAL_INDEX)); + // Copy the qml global object from the surrounding context. + __ ldr(r1, ContextOperand(cp, Context::QML_GLOBAL_INDEX)); + __ str(r1, ContextOperand(r0, Context::QML_GLOBAL_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 3c8df29..2555c04 100644 --- a/src/3rdparty/v8/src/arm/full-codegen-arm.cc +++ b/src/3rdparty/v8/src/arm/full-codegen-arm.cc @@ -182,12 +182,13 @@ 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 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); @@ -812,6 +813,7 @@ void FullCodeGenerator::VisitVariableDeclaration( globals_->Add(variable->binding_needs_init() ? isolate()->factory()->the_hole_value() : isolate()->factory()->undefined_value()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); break; case Variable::PARAMETER: @@ -873,6 +875,7 @@ void FullCodeGenerator::VisitFunctionDeclaration( // Check for stack-overflow exception. if (function.is_null()) return SetStackOverflow(); globals_->Add(function); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); break; } @@ -928,6 +931,7 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { Comment cmnt(masm_, "[ ModuleDeclaration"); globals_->Add(variable->name()); globals_->Add(instance); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); Visit(declaration->module()); break; } @@ -1330,7 +1334,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 @@ -1417,7 +1421,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); @@ -2084,7 +2088,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(); @@ -2406,8 +2410,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); } @@ -2464,7 +2472,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()) { @@ -3888,7 +3896,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); @@ -4191,7 +4199,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 5c60f53..a679c0c 100644 --- a/src/3rdparty/v8/src/arm/lithium-arm.cc +++ b/src/3rdparty/v8/src/arm/lithium-arm.cc @@ -1126,7 +1126,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())); } @@ -1199,7 +1199,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 dbae813..7e94f88 100644 --- a/src/3rdparty/v8/src/arm/lithium-arm.h +++ b/src/3rdparty/v8/src/arm/lithium-arm.h @@ -1436,13 +1436,17 @@ 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 InputAt(0); } + bool qml_global() { return qml_global_; } + private: + bool qml_global_; }; @@ -1535,10 +1539,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 d224d24..90060a9 100644 --- a/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc +++ b/src/3rdparty/v8/src/arm/lithium-codegen-arm.cc @@ -174,12 +174,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); @@ -3075,7 +3076,7 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { void LCodeGen::DoGlobalObject(LGlobalObject* instr) { Register result = ToRegister(instr->result()); - __ ldr(result, ContextOperand(cp, Context::GLOBAL_INDEX)); + __ ldr(result, ContextOperand(cp, instr->qml_global()?Context::QML_GLOBAL_INDEX:Context::GLOBAL_INDEX)); } diff --git a/src/3rdparty/v8/src/arm/macro-assembler-arm.h b/src/3rdparty/v8/src/arm/macro-assembler-arm.h index 360f4c1..5a5469f 100644 --- a/src/3rdparty/v8/src/arm/macro-assembler-arm.h +++ b/src/3rdparty/v8/src/arm/macro-assembler-arm.h @@ -1372,6 +1372,11 @@ inline MemOperand GlobalObjectOperand() { } +static inline MemOperand QmlGlobalObjectOperand() { + return ContextOperand(cp, Context::QML_GLOBAL_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 6f9fd7a..a02cede 100644 --- a/src/3rdparty/v8/src/ast.cc +++ b/src/3rdparty/v8/src/ast.cc @@ -171,6 +171,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) { @@ -549,6 +554,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 dad8057..d2785c2 100644 --- a/src/3rdparty/v8/src/ast.h +++ b/src/3rdparty/v8/src/ast.h @@ -2047,6 +2047,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 048a027..36260ba 100644 --- a/src/3rdparty/v8/src/bootstrapper.cc +++ b/src/3rdparty/v8/src/bootstrapper.cc @@ -809,6 +809,7 @@ void Genesis::HookUpInnerGlobal(Handle<GlobalObject> inner_global) { Handle<JSBuiltinsObject> builtins_global(global_context_->builtins()); global_context_->set_extension(*inner_global); global_context_->set_global(*inner_global); + global_context_->set_qml_global(*inner_global); global_context_->set_security_token(*inner_global); static const PropertyAttributes attributes = static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE); @@ -834,6 +835,7 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global, // Set extension and global object. global_context()->set_extension(*inner_global); global_context()->set_global(*inner_global); + global_context()->set_qml_global(*inner_global); // Security setup: Set the security token of the global object to // its the inner global. This makes the security check between two // different contexts fail by default even in case of global diff --git a/src/3rdparty/v8/src/code-stubs.h b/src/3rdparty/v8/src/code-stubs.h index 5c87178..e281a36 100644 --- a/src/3rdparty/v8/src/code-stubs.h +++ b/src/3rdparty/v8/src/code-stubs.h @@ -343,7 +343,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); @@ -361,7 +361,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 ecac5cb..88b477d 100644 --- a/src/3rdparty/v8/src/compiler.cc +++ b/src/3rdparty/v8/src/compiler.cc @@ -475,7 +475,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); @@ -527,6 +528,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()) { compilation_cache->PutScript(source, result); @@ -546,7 +548,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); @@ -572,6 +575,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.SetCallingContext(context); result = MakeFunctionInfo(&info); if (!result.is_null()) { @@ -626,6 +630,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()) { @@ -775,6 +785,7 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info, *lit->this_property_assignments()); function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); 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 44df9e0..09583c0 100644 --- a/src/3rdparty/v8/src/compiler.h +++ b/src/3rdparty/v8/src/compiler.h @@ -58,6 +58,7 @@ class CompilationInfo BASE_EMBEDDED { 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_; } @@ -88,6 +89,9 @@ class CompilationInfo BASE_EMBEDDED { ASSERT(is_lazy()); flags_ |= IsInLoop::encode(true); } + void MarkAsQmlMode() { + flags_ |= IsQmlMode::encode(true); + } void MarkAsNative() { flags_ |= IsNative::encode(true); } @@ -196,6 +200,9 @@ class CompilationInfo BASE_EMBEDDED { ASSERT(language_mode() == CLASSIC_MODE); SetLanguageMode(shared_info_->language_mode()); } + if (!shared_info_.is_null() && shared_info_->qml_mode()) { + MarkAsQmlMode(); + } } void SetMode(Mode mode) { @@ -222,7 +229,8 @@ class CompilationInfo BASE_EMBEDDED { // 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_; @@ -292,14 +300,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 76784bd..cf07cc6 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()->IsUndefined()) { + qml_global = Handle<JSObject>(context->qml_global(), isolate); + qml_global_global = Handle<JSObject>(context->global(), isolate); + } + // 1. Check global objects, subjects of with, and extension objects. if (context->IsGlobalContext() || 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 647c15c..18f73d9 100644 --- a/src/3rdparty/v8/src/contexts.h +++ b/src/3rdparty/v8/src/contexts.h @@ -221,6 +221,7 @@ class Context: public FixedArray { // (with contexts), or the variable name (catch contexts), the serialized // scope info (block contexts). EXTENSION_INDEX, + QML_GLOBAL_INDEX, GLOBAL_INDEX, MIN_CONTEXT_SLOTS, @@ -327,6 +328,9 @@ class Context: public FixedArray { } void set_global(GlobalObject* global) { set(GLOBAL_INDEX, global); } + JSObject *qml_global() { return reinterpret_cast<JSObject *>(get(QML_GLOBAL_INDEX)); } + void set_qml_global(JSObject *qml_global) { set(QML_GLOBAL_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 5618975..7e69abe 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()->IsGlobalObject()); + Handle<JSObject> oldqml; + if (!qml.is_null()) { + oldqml = Handle<JSObject>(function->context()->qml_global()); + function->context()->set_qml_global(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(*oldqml); + #ifdef DEBUG value->Verify(); #endif @@ -146,7 +156,18 @@ 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()) { @@ -170,7 +191,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); } @@ -179,7 +200,7 @@ Handle<Object> Execution::New(Handle<JSFunction> func, Handle<Object> argv[], bool* pending_exception) { return Invoke(true, func, Isolate::Current()->global(), argc, argv, - pending_exception); + pending_exception, Handle<Object>()); } @@ -198,7 +219,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 01e4b9d..c33a675 100644 --- a/src/3rdparty/v8/src/execution.h +++ b/src/3rdparty/v8/src/execution.h @@ -69,6 +69,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 0e0ffe9..a89b446 100644 --- a/src/3rdparty/v8/src/full-codegen.h +++ b/src/3rdparty/v8/src/full-codegen.h @@ -547,6 +547,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 97b033f..54d628e 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 73f291c..933cec6 100644 --- a/src/3rdparty/v8/src/heap.cc +++ b/src/3rdparty/v8/src/heap.cc @@ -4867,6 +4867,7 @@ MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) { context->set_previous(function->context()); context->set_extension(NULL); context->set_global(function->context()->global()); + context->set_qml_global(function->context()->qml_global()); return context; } @@ -4887,6 +4888,7 @@ MaybeObject* Heap::AllocateCatchContext(JSFunction* function, context->set_previous(previous); context->set_extension(name); context->set_global(previous->global()); + context->set_qml_global(previous->qml_global()); context->set(Context::THROWN_OBJECT_INDEX, thrown_object); return context; } @@ -4905,6 +4907,7 @@ MaybeObject* Heap::AllocateWithContext(JSFunction* function, context->set_previous(previous); context->set_extension(extension); context->set_global(previous->global()); + context->set_qml_global(previous->qml_global()); return context; } @@ -4923,6 +4926,7 @@ MaybeObject* Heap::AllocateBlockContext(JSFunction* function, context->set_previous(previous); context->set_extension(scope_info); context->set_global(previous->global()); + context->set_qml_global(previous->qml_global()); return context; } diff --git a/src/3rdparty/v8/src/hydrogen-instructions.cc b/src/3rdparty/v8/src/hydrogen-instructions.cc index c66a7a1..26f7f7a 100644 --- a/src/3rdparty/v8/src/hydrogen-instructions.cc +++ b/src/3rdparty/v8/src/hydrogen-instructions.cc @@ -685,6 +685,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 4f21db7..c2c51ca 100644 --- a/src/3rdparty/v8/src/hydrogen-instructions.h +++ b/src/3rdparty/v8/src/hydrogen-instructions.h @@ -1550,19 +1550,30 @@ 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: + bool qml_global_; }; @@ -1754,7 +1765,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); @@ -1766,10 +1777,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 99beda0..cfe80d2 100644 --- a/src/3rdparty/v8/src/hydrogen.cc +++ b/src/3rdparty/v8/src/hydrogen.cc @@ -4183,6 +4183,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, @@ -4811,6 +4812,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, @@ -6709,11 +6711,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); } @@ -7769,6 +7773,7 @@ void HGraphBuilder::VisitVariableDeclaration(VariableDeclaration* declaration) { globals_.Add(variable->binding_needs_init() ? isolate()->factory()->the_hole_value() : isolate()->factory()->undefined_value()); + globals_.Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); return; case Variable::PARAMETER: case Variable::LOCAL: @@ -7804,6 +7809,7 @@ void HGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* declaration) { // Check for stack-overflow exception. if (function.is_null()) return SetStackOverflow(); globals_.Add(function); + globals_.Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); 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 a1c6edd..7224b07 100644 --- a/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc +++ b/src/3rdparty/v8/src/ia32/code-stubs-ia32.cc @@ -145,6 +145,11 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX))); __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); + // Copy the qml global object from the previous context. + __ mov(ebx, Operand(esi, Context::SlotOffset(Context::QML_GLOBAL_INDEX))); + __ mov(Operand(eax, Context::SlotOffset(Context::QML_GLOBAL_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++) { @@ -211,6 +216,10 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) { __ mov(ebx, ContextOperand(esi, Context::GLOBAL_INDEX)); __ mov(ContextOperand(eax, Context::GLOBAL_INDEX), ebx); + // Copy the qml global object from the previous context. + __ mov(ebx, ContextOperand(esi, Context::QML_GLOBAL_INDEX)); + __ mov(ContextOperand(eax, Context::QML_GLOBAL_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 266afce..66cf497 100644 --- a/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc +++ b/src/3rdparty/v8/src/ia32/full-codegen-ia32.cc @@ -175,12 +175,13 @@ 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 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); @@ -786,6 +787,7 @@ void FullCodeGenerator::VisitVariableDeclaration( globals_->Add(variable->binding_needs_init() ? isolate()->factory()->the_hole_value() : isolate()->factory()->undefined_value()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); 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); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); break; } @@ -898,6 +901,7 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { Comment cmnt(masm_, "[ ModuleDeclaration"); globals_->Add(variable->name()); globals_->Add(instance); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); Visit(declaration->module()); break; } @@ -1286,7 +1290,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) @@ -1370,7 +1374,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); @@ -2037,7 +2041,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(); @@ -2348,8 +2352,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); } @@ -2402,7 +2409,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()) { @@ -3859,7 +3866,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); @@ -4180,7 +4187,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 fa58146..cf30156 100644 --- a/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.cc +++ b/src/3rdparty/v8/src/ia32/lithium-codegen-ia32.cc @@ -186,12 +186,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); @@ -2734,7 +2735,7 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { void LCodeGen::DoGlobalObject(LGlobalObject* instr) { Register context = ToRegister(instr->context()); Register result = ToRegister(instr->result()); - __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ mov(result, Operand(context, Context::SlotOffset(instr->qml_global()?Context::QML_GLOBAL_INDEX:Context::GLOBAL_INDEX))); } diff --git a/src/3rdparty/v8/src/ia32/lithium-ia32.cc b/src/3rdparty/v8/src/ia32/lithium-ia32.cc index d0cb230..fb408a1 100644 --- a/src/3rdparty/v8/src/ia32/lithium-ia32.cc +++ b/src/3rdparty/v8/src/ia32/lithium-ia32.cc @@ -1143,7 +1143,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())); } @@ -1233,7 +1233,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 be64b2f..16b5610 100644 --- a/src/3rdparty/v8/src/ia32/lithium-ia32.h +++ b/src/3rdparty/v8/src/ia32/lithium-ia32.h @@ -1449,13 +1449,17 @@ 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; } DECLARE_CONCRETE_INSTRUCTION(GlobalObject, "global-object") LOperand* context() { return InputAt(0); } + bool qml_global() { return qml_global_; } + private: + bool qml_global_; }; @@ -1557,7 +1561,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; } @@ -1569,6 +1573,10 @@ class LCallGlobal: public LTemplateInstruction<1, 1, 0> { LOperand* context() { return inputs_[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 66d1ce7..1cc9142 100644 --- a/src/3rdparty/v8/src/ia32/macro-assembler-ia32.h +++ b/src/3rdparty/v8/src/ia32/macro-assembler-ia32.h @@ -946,6 +946,9 @@ inline Operand GlobalObjectOperand() { return ContextOperand(esi, Context::GLOBAL_INDEX); } +static inline Operand QmlGlobalObjectOperand() { + return ContextOperand(esi, Context::QML_GLOBAL_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 9772b94..be5f752 100644 --- a/src/3rdparty/v8/src/ic.cc +++ b/src/3rdparty/v8/src/ic.cc @@ -675,7 +675,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 3b44abf..36af768 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(); + 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 f3dd95b..abe9df6 100644 --- a/src/3rdparty/v8/src/mips/code-stubs-mips.cc +++ b/src/3rdparty/v8/src/mips/code-stubs-mips.cc @@ -171,6 +171,11 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { __ sw(a1, MemOperand(v0, Context::SlotOffset(Context::EXTENSION_INDEX))); __ sw(a2, MemOperand(v0, Context::SlotOffset(Context::GLOBAL_INDEX))); + // Copy the qml global object from the surrounding context. + __ lw(a1, MemOperand(cp, Context::SlotOffset(Context::QML_GLOBAL_INDEX))); + __ sw(a1, MemOperand(v0, Context::SlotOffset(Context::QML_GLOBAL_INDEX))); + + // Initialize the rest of the slots to undefined. __ LoadRoot(a1, Heap::kUndefinedValueRootIndex); for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { @@ -233,6 +238,10 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) { __ sw(a1, ContextOperand(v0, Context::EXTENSION_INDEX)); __ sw(a2, ContextOperand(v0, Context::GLOBAL_INDEX)); + // Copy the qml global object from the surrounding context. + __ lw(a1, ContextOperand(cp, Context::QML_GLOBAL_INDEX)); + __ sw(a1, ContextOperand(v0, Context::QML_GLOBAL_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 7be5056..842232a 100644 --- a/src/3rdparty/v8/src/mips/full-codegen-mips.cc +++ b/src/3rdparty/v8/src/mips/full-codegen-mips.cc @@ -189,12 +189,13 @@ 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 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); @@ -821,6 +822,7 @@ void FullCodeGenerator::VisitVariableDeclaration( globals_->Add(variable->binding_needs_init() ? isolate()->factory()->the_hole_value() : isolate()->factory()->undefined_value()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); break; case Variable::PARAMETER: @@ -883,6 +885,7 @@ void FullCodeGenerator::VisitFunctionDeclaration( // Check for stack-overflow exception. if (function.is_null()) return SetStackOverflow(); globals_->Add(function); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); break; } @@ -938,6 +941,7 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { Comment cmnt(masm_, "[ ModuleDeclaration"); globals_->Add(variable->name()); globals_->Add(instance); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); Visit(declaration->module()); break; } @@ -1336,7 +1340,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 @@ -1423,7 +1427,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); @@ -2101,7 +2105,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(); @@ -2431,8 +2435,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); } @@ -2488,7 +2496,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()) { @@ -3929,7 +3937,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); @@ -4235,7 +4243,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 a4de721..d016743 100644 --- a/src/3rdparty/v8/src/mips/lithium-codegen-mips.cc +++ b/src/3rdparty/v8/src/mips/lithium-codegen-mips.cc @@ -172,12 +172,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); @@ -2829,7 +2830,7 @@ void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) { void LCodeGen::DoGlobalObject(LGlobalObject* instr) { Register result = ToRegister(instr->result()); - __ lw(result, ContextOperand(cp, Context::GLOBAL_INDEX)); + __ lw(result, ContextOperand(cp, instr->qml_global()?Context::QML_GLOBAL_INDEX:Context::GLOBAL_INDEX)); } diff --git a/src/3rdparty/v8/src/mips/lithium-mips.cc b/src/3rdparty/v8/src/mips/lithium-mips.cc index 1eb3ab7..eab5945 100644 --- a/src/3rdparty/v8/src/mips/lithium-mips.cc +++ b/src/3rdparty/v8/src/mips/lithium-mips.cc @@ -1125,7 +1125,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())); } @@ -1200,7 +1200,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 a04b429..62c5398 100644 --- a/src/3rdparty/v8/src/mips/lithium-mips.h +++ b/src/3rdparty/v8/src/mips/lithium-mips.h @@ -1399,13 +1399,17 @@ 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 InputAt(0); } + bool qml_global() { return qml_global_; } + private: + bool qml_global_; }; @@ -1498,10 +1502,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 f57418f..b5897e4 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_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 3c54afc..194e7ad 100644 --- a/src/3rdparty/v8/src/objects-inl.h +++ b/src/3rdparty/v8/src/objects-inl.h @@ -3823,6 +3823,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 a2884ca..120b24a 100644 --- a/src/3rdparty/v8/src/objects.h +++ b/src/3rdparty/v8/src/objects.h @@ -3353,6 +3353,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); @@ -3375,7 +3378,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(); @@ -3524,8 +3527,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. @@ -5423,6 +5427,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) @@ -5665,6 +5672,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 8620519..b26a9f9 100644 --- a/src/3rdparty/v8/src/parser.cc +++ b/src/3rdparty/v8/src/parser.cc @@ -617,6 +617,9 @@ FunctionLiteral* Parser::DoParseProgram(CompilationInfo* info, scope->set_end_position(source->length()); FunctionState function_state(this, scope, isolate()); top_scope_->SetLanguageMode(info->language_mode()); + if (info->is_qml_mode()) { + scope->EnableQmlModeFlag(); + } ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(16); bool ok = true; int beg_loc = scanner().location().beg_pos; @@ -715,6 +718,9 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, 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 @@ -2296,6 +2302,11 @@ Block* Parser::ParseVariableDeclarations( arguments->Add(value); value = NULL; // zap the value to avoid the unnecessary assignment + int qml_mode = 0; + if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name)) + qml_mode = 1; + arguments->Add(factory()->NewNumberLiteral(qml_mode)); + // Construct the call to Runtime_InitializeConstGlobal // and add it to the initialization statement block. // Note that the function does different things depending on @@ -2310,6 +2321,11 @@ Block* Parser::ParseVariableDeclarations( LanguageMode language_mode = initialization_scope->language_mode(); arguments->Add(factory()->NewNumberLiteral(language_mode)); + int qml_mode = 0; + if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name)) + qml_mode = 1; + arguments->Add(factory()->NewNumberLiteral(qml_mode)); + // 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 5adea6e..63acc4c 100644 --- a/src/3rdparty/v8/src/runtime.cc +++ b/src/3rdparty/v8/src/runtime.cc @@ -1272,19 +1272,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()); 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()); + Handle<JSObject> qml_global = Handle<JSObject>(isolate->context()->qml_global()); + // 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 = @@ -1477,20 +1482,25 @@ 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(); 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():isolate->context()->global(); + // According to ECMA-262, section 12.2, page 62, the property must // not be deletable. PropertyAttributes attributes = DONT_DELETE; @@ -1518,7 +1528,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(); } @@ -1528,10 +1538,10 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { } // Reload global in case the loop above performed a GC. - global = isolate->context()->global(); + global = qml_mode?isolate->context()->qml_global():isolate->context()->global(); if (assign) { return global->SetProperty( - *name, args[2], attributes, strict_mode_flag, true); + *name, args[3], attributes, strict_mode_flag, true); } return isolate->heap()->undefined_value(); } @@ -1541,12 +1551,15 @@ 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(); + JSObject* global = qml_mode?isolate->context()->qml_global():isolate->context()->global(); // 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. @@ -1570,7 +1583,7 @@ 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()); + Handle<JSObject> global(qml_mode?isolate->context()->qml_global():isolate->context()->global()); // BUG 1213575: Handle the case where we have to set a read-only // property through an interceptor and only do it if it's @@ -8576,7 +8589,10 @@ 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()); + Object* result; { MaybeObject* maybe_result = isolate->heap()->AllocateFunctionContext(length, function); @@ -9255,7 +9271,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { // Compile source string in the global 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, @@ -9269,7 +9285,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> global_context = Handle<Context>(context->global_context()); @@ -9289,7 +9306,8 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, Handle<Context>(isolate->context()), context->IsGlobalContext(), language_mode, - scope_position); + scope_position, + qml_mode); if (shared.is_null()) return MakePair(Failure::Exception(), NULL); Handle<JSFunction> compiled = isolate->factory()->NewFunctionFromSharedFunctionInfo( @@ -9299,7 +9317,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); @@ -9320,7 +9338,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()); } @@ -11957,6 +11976,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. @@ -12028,7 +12048,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { context, context->IsGlobalContext(), CLASSIC_MODE, - RelocInfo::kNoPosition); + RelocInfo::kNoPosition, + qml_mode); if (shared.is_null()) return Failure::Exception(); Handle<JSFunction> compiled_function = isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context); @@ -12038,7 +12059,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())); if (has_pending_exception) return Failure::Exception(); Handle<Object> arguments = GetArgumentsObject(isolate, @@ -12121,7 +12143,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 83991bb..fed04cf 100644 --- a/src/3rdparty/v8/src/runtime.h +++ b/src/3rdparty/v8/src/runtime.h @@ -260,7 +260,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) \ @@ -335,8 +335,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 f50af30..a1f8339 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) { 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 = @@ -194,7 +200,9 @@ int ScopeInfo::ContextLength() { function_name_context_slot || Type() == WITH_SCOPE || (Type() == FUNCTION_SCOPE && CallsEval()); - 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 2c61a75..6580378 100644 --- a/src/3rdparty/v8/src/scopes.cc +++ b/src/3rdparty/v8/src/scopes.cc @@ -36,6 +36,8 @@ #include "allocation-inl.h" +#include "debug.h" + namespace v8 { namespace internal { @@ -184,6 +186,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; @@ -984,6 +988,25 @@ bool Scope::ResolveVariable(CompilationInfo* info, // debugger to evaluate arbitrary expressions at a break point). if (var->is_global()) { var = NonLocal(proxy->name(), DYNAMIC_GLOBAL); + + if (is_qml_mode()) { + Handle<GlobalObject> global = isolate_->global(); + +#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()); + } +#endif + + if (is_qml_mode() && !global->HasProperty(*(proxy->name()))) { + var->set_is_qml_global(true); + } + } } else if (var->is_dynamic()) { var = NonLocal(proxy->name(), DYNAMIC); } else { @@ -996,12 +1019,52 @@ bool Scope::ResolveVariable(CompilationInfo* info, case UNBOUND: // No binding has been found. Declare a variable in global scope. var = info->global_scope()->DeclareGlobal(proxy->name()); + + if (is_qml_mode()) { + Handle<GlobalObject> global = isolate_->global(); + +#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()); + } +#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(); + +#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()); + } +#endif + + if (is_qml_mode() && !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 be6705b..31847e2 100644 --- a/src/3rdparty/v8/src/scopes.h +++ b/src/3rdparty/v8/src/scopes.h @@ -224,6 +224,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 @@ -278,6 +283,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_; } @@ -302,6 +308,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_; } @@ -462,6 +471,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 bd7163a..af41231 100644 --- a/src/3rdparty/v8/src/stub-cache.cc +++ b/src/3rdparty/v8/src/stub-cache.cc @@ -763,7 +763,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, NORMAL, argc); Handle<UnseededNumberDictionary> cache = @@ -772,7 +773,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; } @@ -1179,13 +1180,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 29bdb61..206dddd 100644 --- a/src/3rdparty/v8/src/stub-cache.h +++ b/src/3rdparty/v8/src/stub-cache.h @@ -219,7 +219,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); @@ -410,7 +411,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 32ad5bc..4984cbd 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 f49b6e1..43b2c81 100644 --- a/src/3rdparty/v8/src/variables.h +++ b/src/3rdparty/v8/src/variables.h @@ -164,6 +164,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_; @@ -189,6 +192,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 d179d2a..9b9906b 100644 --- a/src/3rdparty/v8/src/x64/code-stubs-x64.cc +++ b/src/3rdparty/v8/src/x64/code-stubs-x64.cc @@ -139,6 +139,10 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX))); __ movq(Operand(rax, Context::SlotOffset(Context::GLOBAL_INDEX)), rbx); + // Copy the qmlglobal object from the previous context. + __ movq(rbx, Operand(rsi, Context::SlotOffset(Context::QML_GLOBAL_INDEX))); + __ movq(Operand(rax, Context::SlotOffset(Context::QML_GLOBAL_INDEX)), rbx); + // Initialize the rest of the slots to undefined. __ LoadRoot(rbx, Heap::kUndefinedValueRootIndex); for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { @@ -203,6 +207,10 @@ void FastNewBlockContextStub::Generate(MacroAssembler* masm) { __ movq(rbx, ContextOperand(rsi, Context::GLOBAL_INDEX)); __ movq(ContextOperand(rax, Context::GLOBAL_INDEX), rbx); + // Copy the qmlglobal object from the previous context. + __ movq(rbx, ContextOperand(rsi, Context::QML_GLOBAL_INDEX)); + __ movq(ContextOperand(rax, Context::QML_GLOBAL_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 974269e..22f2ebb 100644 --- a/src/3rdparty/v8/src/x64/full-codegen-x64.cc +++ b/src/3rdparty/v8/src/x64/full-codegen-x64.cc @@ -171,12 +171,13 @@ 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 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); @@ -783,6 +784,7 @@ void FullCodeGenerator::VisitVariableDeclaration( globals_->Add(variable->binding_needs_init() ? isolate()->factory()->the_hole_value() : isolate()->factory()->undefined_value()); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); break; case Variable::PARAMETER: @@ -843,6 +845,7 @@ void FullCodeGenerator::VisitFunctionDeclaration( // Check for stack-overflow exception. if (function.is_null()) return SetStackOverflow(); globals_->Add(function); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); break; } @@ -896,6 +899,7 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) { Comment cmnt(masm_, "[ ModuleDeclaration"); globals_->Add(variable->name()); globals_->Add(instance); + globals_->Add(isolate()->factory()->ToBoolean(variable->is_qml_global())); Visit(declaration->module()); break; } @@ -1298,7 +1302,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) @@ -1383,7 +1387,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); @@ -2010,7 +2014,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(); @@ -2313,8 +2317,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); } @@ -2367,7 +2374,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). @@ -3841,7 +3848,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); @@ -4163,7 +4170,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 d1cf338..d34a520 100644 --- a/src/3rdparty/v8/src/x64/lithium-codegen-x64.cc +++ b/src/3rdparty/v8/src/x64/lithium-codegen-x64.cc @@ -184,12 +184,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); @@ -2706,7 +2707,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 3ba0cae..6d723a5 100644 --- a/src/3rdparty/v8/src/x64/lithium-x64.cc +++ b/src/3rdparty/v8/src/x64/lithium-x64.cc @@ -1119,7 +1119,7 @@ LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) { LInstruction* LChunkBuilder::DoGlobalObject(HGlobalObject* instr) { - return DefineAsRegister(new(zone()) LGlobalObject); + return DefineAsRegister(new(zone()) LGlobalObject(instr->qml_global())); } @@ -1189,7 +1189,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 642a0a0..ac1a5db 100644 --- a/src/3rdparty/v8/src/x64/lithium-x64.h +++ b/src/3rdparty/v8/src/x64/lithium-x64.h @@ -1400,7 +1400,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_; }; @@ -1494,10 +1500,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 66587d5..5ec8873 100644 --- a/src/3rdparty/v8/src/x64/macro-assembler-x64.h +++ b/src/3rdparty/v8/src/x64/macro-assembler-x64.h @@ -1445,6 +1445,11 @@ inline Operand GlobalObjectOperand() { } +static inline Operand QmlGlobalObjectOperand() { + return ContextOperand(rsi, Context::QML_GLOBAL_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 8a1e914..9122781 100644 --- a/src/3rdparty/v8/test/cctest/test-api.cc +++ b/src/3rdparty/v8/test/cctest/test-api.cc @@ -14396,6 +14396,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. @@ -14420,10 +14421,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. @@ -14442,10 +14443,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. @@ -14469,10 +14470,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(); } diff --git a/src/3rdparty/v8/test/cctest/test-heap-profiler.cc b/src/3rdparty/v8/test/cctest/test-heap-profiler.cc index cbe8d44..b5815dc 100644 --- a/src/3rdparty/v8/test/cctest/test-heap-profiler.cc +++ b/src/3rdparty/v8/test/cctest/test-heap-profiler.cc @@ -57,9 +57,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; @@ -650,15 +652,29 @@ 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[parsed.nodes[edges_index_offset]" - " + 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[parsed.nodes[edges_index_offset]" + " + 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[parsed.nodes[edges_index_offset]" + " + 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()); @@ -1578,6 +1594,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 d4a40bf..baee7e4 100644 --- a/src/3rdparty/v8/test/cctest/test-heap.cc +++ b/src/3rdparty/v8/test/cctest/test-heap.cc @@ -9,6 +9,7 @@ #include "macro-assembler.h" #include "global-handles.h" #include "cctest.h" +#include "snapshot.h" using namespace v8::internal; @@ -1360,13 +1361,14 @@ static int NumberOfGlobalObjects() { // optimized code. TEST(LeakGlobalContextViaMap) { 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; @@ -1386,7 +1388,7 @@ TEST(LeakGlobalContextViaMap) { ctx1.Dispose(); } HEAP->CollectAllAvailableGarbage(); - CHECK_EQ(2, NumberOfGlobalObjects()); + CHECK_EQ((snapshot_enabled ? 3 : 2), NumberOfGlobalObjects()); ctx2.Dispose(); HEAP->CollectAllAvailableGarbage(); CHECK_EQ(0, NumberOfGlobalObjects()); @@ -1397,13 +1399,14 @@ TEST(LeakGlobalContextViaMap) { // optimized code. TEST(LeakGlobalContextViaFunction) { 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; @@ -1423,7 +1426,7 @@ TEST(LeakGlobalContextViaFunction) { ctx1.Dispose(); } HEAP->CollectAllAvailableGarbage(); - CHECK_EQ(2, NumberOfGlobalObjects()); + CHECK_EQ((snapshot_enabled ? 3 : 2), NumberOfGlobalObjects()); ctx2.Dispose(); HEAP->CollectAllAvailableGarbage(); CHECK_EQ(0, NumberOfGlobalObjects()); @@ -1432,13 +1435,14 @@ TEST(LeakGlobalContextViaFunction) { TEST(LeakGlobalContextViaMapKeyed) { 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; @@ -1458,7 +1462,7 @@ TEST(LeakGlobalContextViaMapKeyed) { ctx1.Dispose(); } HEAP->CollectAllAvailableGarbage(); - CHECK_EQ(2, NumberOfGlobalObjects()); + CHECK_EQ((snapshot_enabled ? 3 : 2), NumberOfGlobalObjects()); ctx2.Dispose(); HEAP->CollectAllAvailableGarbage(); CHECK_EQ(0, NumberOfGlobalObjects()); @@ -1467,13 +1471,14 @@ TEST(LeakGlobalContextViaMapKeyed) { TEST(LeakGlobalContextViaMapProto) { 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; @@ -1497,7 +1502,7 @@ TEST(LeakGlobalContextViaMapProto) { ctx1.Dispose(); } HEAP->CollectAllAvailableGarbage(); - CHECK_EQ(2, NumberOfGlobalObjects()); + CHECK_EQ((snapshot_enabled ? 3 : 2), NumberOfGlobalObjects()); ctx2.Dispose(); HEAP->CollectAllAvailableGarbage(); CHECK_EQ(0, NumberOfGlobalObjects()); |