diff options
author | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-05-11 17:20:40 +1000 |
---|---|---|
committer | Aaron Kennedy <aaron.kennedy@nokia.com> | 2011-06-06 11:50:48 +1000 |
commit | 6b54de600ce74025bc8ada20bea95ad183a6cd8d (patch) | |
tree | 6736888525cd8cd8c2d30bb7b87b3249b74839a5 /src/v8/0005-Introduce-a-QML-compilation-mode.patch | |
parent | 6dbd4286eb19e9ac45665046a43342bcdc8b127e (diff) |
Initial V8 integration
Diffstat (limited to 'src/v8/0005-Introduce-a-QML-compilation-mode.patch')
-rw-r--r-- | src/v8/0005-Introduce-a-QML-compilation-mode.patch | 1369 |
1 files changed, 1369 insertions, 0 deletions
diff --git a/src/v8/0005-Introduce-a-QML-compilation-mode.patch b/src/v8/0005-Introduce-a-QML-compilation-mode.patch new file mode 100644 index 0000000000..2b49648337 --- /dev/null +++ b/src/v8/0005-Introduce-a-QML-compilation-mode.patch @@ -0,0 +1,1369 @@ +From 6311077b6acd840a5b877e293fdc8eda3f83701e Mon Sep 17 00:00:00 2001 +From: Aaron Kennedy <aaron.kennedy@nokia.com> +Date: Mon, 23 May 2011 18:26:19 +1000 +Subject: [PATCH 5/7] 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 resolve 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. +--- + include/v8.h | 18 ++++++++-- + src/api.cc | 46 +++++++++++++++++++++----- + src/ast-inl.h | 5 +++ + src/ast.h | 1 + + src/compiler.cc | 15 +++++++- + src/compiler.h | 24 +++++++++++--- + src/contexts.cc | 23 +++++++++++++ + src/contexts.h | 4 ++ + src/execution.cc | 28 ++++++++++++++-- + src/execution.h | 6 +++ + src/full-codegen.cc | 3 +- + src/full-codegen.h | 1 + + src/heap.cc | 2 + + src/ia32/code-stubs-ia32.cc | 7 ++++ + src/ia32/full-codegen-ia32.cc | 21 +++++++----- + src/ia32/macro-assembler-ia32.h | 5 +++ + src/objects-inl.h | 12 +++++++ + src/objects.h | 5 +++ + src/parser.cc | 27 +++++++++++++-- + src/parser.h | 4 ++- + src/prettyprinter.cc | 3 ++ + src/runtime.cc | 68 +++++++++++++++++++++++++-------------- + src/runtime.h | 8 ++-- + src/scopes.cc | 16 +++++++++ + src/scopes.h | 7 ++++ + src/variables.cc | 3 +- + src/variables.h | 5 +++ + src/x64/code-stubs-x64.cc | 4 ++ + src/x64/full-codegen-x64.cc | 21 +++++++----- + src/x64/macro-assembler-x64.h | 5 +++ + 30 files changed, 320 insertions(+), 77 deletions(-) + +diff --git a/include/v8.h b/include/v8.h +index eaa0ec4..62715ec 100644 +--- a/include/v8.h ++++ b/include/v8.h +@@ -577,6 +577,10 @@ class ScriptOrigin { + */ + class V8EXPORT Script { + public: ++ enum CompileFlags { ++ Default = 0x00, ++ QmlMode = 0x01 ++ }; + + /** + * Compiles the specified script (context-independent). +@@ -596,7 +600,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 +@@ -609,7 +614,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). +@@ -630,7 +636,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 +@@ -647,7 +654,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 +@@ -657,6 +665,7 @@ class V8EXPORT Script { + * compiled. + */ + Local<Value> Run(); ++ Local<Value> Run(Handle<Object> qml); + + /** + * Returns the script id value. +@@ -3299,6 +3308,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/api.cc b/src/api.cc +index f62c5a0..e2efcaa 100644 +--- a/src/api.cc ++++ b/src/api.cc +@@ -1372,7 +1372,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"); +@@ -1409,7 +1410,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>()); + return Local<Script>(ToApi<Script>(result)); +@@ -1417,21 +1419,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); +@@ -1447,13 +1451,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"); +@@ -1472,10 +1481,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, qmlglobal); + EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>()); + raw_result = *result; + } +@@ -3915,6 +3925,24 @@ 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::JavaScriptFrameIterator it; ++ if (it.done()) return Local<Object>(); ++ i::Context *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/ast-inl.h b/src/ast-inl.h +index d80684a..adc5a1f 100644 +--- a/src/ast-inl.h ++++ b/src/ast-inl.h +@@ -106,6 +106,11 @@ bool FunctionLiteral::strict_mode() const { + } + + ++bool FunctionLiteral::qml_mode() const { ++ return scope()->is_qml_mode(); ++} ++ ++ + } } // namespace v8::internal + + #endif // V8_AST_INL_H_ +diff --git a/src/ast.h b/src/ast.h +index 65a25a9..f790dc0 100644 +--- a/src/ast.h ++++ b/src/ast.h +@@ -1712,6 +1712,7 @@ class FunctionLiteral: public Expression { + int end_position() const { return end_position_; } + bool is_expression() const { return is_expression_; } + bool strict_mode() const; ++ bool qml_mode() const; + + int materialized_literal_count() { return materialized_literal_count_; } + int expected_property_count() { return expected_property_count_; } +diff --git a/src/compiler.cc b/src/compiler.cc +index 86d5de3..d2191b9 100755 +--- a/src/compiler.cc ++++ b/src/compiler.cc +@@ -462,7 +462,8 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, + v8::Extension* extension, + ScriptDataImpl* input_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); +@@ -523,6 +524,7 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, + info.MarkAsGlobal(); + info.SetExtension(extension); + info.SetPreParseData(pre_data); ++ if (compile_flags & v8::Script::QmlMode) info.MarkAsQmlMode(); + if (natives == NATIVES_CODE) info.MarkAsAllowingNativesSyntax(); + result = MakeFunctionInfo(&info); + if (extension == NULL && !result.is_null()) { +@@ -543,7 +545,8 @@ Handle<SharedFunctionInfo> Compiler::Compile(Handle<String> source, + Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, + Handle<Context> context, + bool is_global, +- StrictModeFlag strict_mode) { ++ StrictModeFlag strict_mode, ++ bool qml_mode) { + Isolate* isolate = source->GetIsolate(); + int source_length = source->length(); + isolate->counters()->total_eval_size()->Increment(source_length); +@@ -567,6 +570,7 @@ Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source, + CompilationInfo info(script); + info.MarkAsEval(); + if (is_global) info.MarkAsGlobal(); ++ if (qml_mode) info.MarkAsQmlMode(); + if (strict_mode == kStrictMode) info.MarkAsStrictMode(); + info.SetCallingContext(context); + result = MakeFunctionInfo(&info); +@@ -610,6 +614,12 @@ bool Compiler::CompileLazy(CompilationInfo* info) { + info->MarkAsStrictMode(); + } + ++ // 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()) { +@@ -755,6 +765,7 @@ void Compiler::SetFunctionInfo(Handle<SharedFunctionInfo> function_info, + *lit->this_property_assignments()); + function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation()); + function_info->set_strict_mode(lit->strict_mode()); ++ function_info->set_qml_mode(lit->qml_mode()); + } + + +diff --git a/src/compiler.h b/src/compiler.h +index e75e869..ca4b62d 100644 +--- a/src/compiler.h ++++ b/src/compiler.h +@@ -54,6 +54,7 @@ class CompilationInfo BASE_EMBEDDED { + bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; } + bool is_strict_mode() const { return (flags_ & IsStrictMode::mask()) != 0; } + bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; } ++ bool is_qml_mode() const { return (flags_ & IsQmlMode::mask()) != 0; } + FunctionLiteral* function() const { return function_; } + Scope* scope() const { return scope_; } + Handle<Code> code() const { return code_; } +@@ -83,6 +84,9 @@ class CompilationInfo BASE_EMBEDDED { + ASSERT(is_lazy()); + flags_ |= IsInLoop::encode(true); + } ++ void MarkAsQmlMode() { ++ flags_ |= IsQmlMode::encode(true); ++ } + void MarkAsAllowingNativesSyntax() { + flags_ |= IsNativesSyntaxAllowed::encode(true); + } +@@ -141,7 +145,8 @@ class CompilationInfo BASE_EMBEDDED { + + // Determine whether or not we can adaptively optimize. + bool AllowOptimize() { +- return V8::UseCrankshaft() && !closure_.is_null(); ++ // XXX - fix qml mode optimizations ++ return V8::UseCrankshaft() && !closure_.is_null() && !is_qml_mode(); + } + + private: +@@ -163,8 +168,13 @@ class CompilationInfo BASE_EMBEDDED { + + void Initialize(Mode mode) { + mode_ = V8::UseCrankshaft() ? mode : NONOPT; +- if (!shared_info_.is_null() && shared_info_->strict_mode()) { +- MarkAsStrictMode(); ++ if (!shared_info_.is_null()) { ++ if (shared_info_->strict_mode()) { ++ MarkAsStrictMode(); ++ } ++ if (shared_info_->qml_mode()) { ++ MarkAsQmlMode(); ++ } + } + } + +@@ -187,6 +197,8 @@ class CompilationInfo BASE_EMBEDDED { + class IsStrictMode: public BitField<bool, 4, 1> {}; + // Native syntax (%-stuff) allowed? + class IsNativesSyntaxAllowed: public BitField<bool, 5, 1> {}; ++ // Qml mode ++ class IsQmlMode: public BitField<bool, 6, 1> {}; + + unsigned flags_; + +@@ -252,13 +264,15 @@ 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 compile_flags = 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, +- StrictModeFlag strict_mode); ++ StrictModeFlag strict_mode, ++ 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/contexts.cc b/src/contexts.cc +index 520f3dd..da5cacb 100644 +--- a/src/contexts.cc ++++ b/src/contexts.cc +@@ -89,6 +89,8 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, + PrintF(")\n"); + } + ++ Handle<JSObject> qml_global; ++ + do { + if (FLAG_trace_contexts) { + PrintF(" - looking in context %p", reinterpret_cast<void*>(*context)); +@@ -119,6 +121,10 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, + } + } + ++ if (qml_global.is_null() && !context->qml_global()->IsUndefined()) { ++ qml_global = Handle<JSObject>(context->qml_global(), isolate); ++ } ++ + if (context->is_function_context()) { + // we have context-local slots + +@@ -198,6 +204,23 @@ Handle<Object> Context::Lookup(Handle<String> name, ContextLookupFlags flags, + } + } while (follow_context_chain); + ++ if (!qml_global.is_null()) { ++ 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; ++ } ++ } ++ + // slot not found + if (FLAG_trace_contexts) { + PrintF("=> no property/slot found\n"); +diff --git a/src/contexts.h b/src/contexts.h +index e46619e..57d8e7b 100644 +--- a/src/contexts.h ++++ b/src/contexts.h +@@ -182,6 +182,7 @@ class Context: public FixedArray { + FCONTEXT_INDEX, + PREVIOUS_INDEX, + EXTENSION_INDEX, ++ QML_GLOBAL_INDEX, + GLOBAL_INDEX, + MIN_CONTEXT_SLOTS, + +@@ -273,6 +274,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/execution.cc b/src/execution.cc +index eb26438..1632076 100644 +--- a/src/execution.cc ++++ b/src/execution.cc +@@ -70,7 +70,8 @@ static Handle<Object> Invoke(bool construct, + Handle<Object> receiver, + int argc, + Object*** args, +- bool* has_pending_exception) { ++ bool* has_pending_exception, ++ Handle<Object> qml) { + Isolate* isolate = func->GetIsolate(); + + // Entering JavaScript. +@@ -107,6 +108,12 @@ static Handle<Object> Invoke(bool construct, + // make the current one is indeed a global object. + ASSERT(func->context()->global()->IsGlobalObject()); + ++ Handle<JSObject> oldqml; ++ if (!qml.is_null()) { ++ oldqml = Handle<JSObject>(func->context()->qml_global()); ++ func->context()->set_qml_global(JSObject::cast(*qml)); ++ } ++ + { + // Save and restore context around invocation and block the + // allocation of handles without explicit handle scopes. +@@ -122,6 +129,9 @@ static Handle<Object> Invoke(bool construct, + receiver_pointer, argc, args); + } + ++ if (!qml.is_null()) ++ func->context()->set_qml_global(*oldqml); ++ + #ifdef DEBUG + value->Verify(); + #endif +@@ -150,14 +160,24 @@ Handle<Object> Execution::Call(Handle<JSFunction> func, + int argc, + Object*** args, + bool* pending_exception) { +- return Invoke(false, func, receiver, argc, args, pending_exception); ++ return Invoke(false, func, receiver, argc, args, pending_exception, Handle<Object>()); ++} ++ ++ ++Handle<Object> Execution::Call(Handle<JSFunction> func, ++ Handle<Object> receiver, ++ int argc, ++ Object*** args, ++ bool* pending_exception, ++ Handle<Object> qml) { ++ return Invoke(false, func, receiver, argc, args, pending_exception, qml); + } + + + Handle<Object> Execution::New(Handle<JSFunction> func, int argc, + Object*** args, bool* pending_exception) { + return Invoke(true, func, Isolate::Current()->global(), argc, args, +- pending_exception); ++ pending_exception, Handle<Object>()); + } + + +@@ -175,7 +195,7 @@ Handle<Object> Execution::TryCall(Handle<JSFunction> func, + catcher.SetCaptureMessage(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/execution.h b/src/execution.h +index d4b80d2..a476eb4 100644 +--- a/src/execution.h ++++ b/src/execution.h +@@ -56,6 +56,12 @@ class Execution : public AllStatic { + int argc, + Object*** args, + bool* pending_exception); ++ static Handle<Object> Call(Handle<JSFunction> func, ++ Handle<Object> receiver, ++ int argc, ++ Object*** args, ++ bool* pending_exception, ++ Handle<Object> qml); + + // Construct object from function, the caller supplies an array of + // arguments. Arguments are Object* type. After function returns, +diff --git a/src/full-codegen.cc b/src/full-codegen.cc +index d6ba56e..2eaef0f 100644 +--- a/src/full-codegen.cc ++++ b/src/full-codegen.cc +@@ -542,7 +542,7 @@ void FullCodeGenerator::VisitDeclarations( + // Do nothing in case of no declared global functions or variables. + if (globals > 0) { + Handle<FixedArray> array = +- isolate()->factory()->NewFixedArray(2 * globals, TENURED); ++ isolate()->factory()->NewFixedArray(3 * globals, TENURED); + for (int j = 0, i = 0; i < length; i++) { + Declaration* decl = declarations->at(i); + Variable* var = decl->proxy()->var(); +@@ -567,6 +567,7 @@ void FullCodeGenerator::VisitDeclarations( + } + array->set(j++, *function); + } ++ array->set(j++, Smi::FromInt(var->is_qml_global())); + } + } + // Invoke the platform-dependent code generator to do the actual +diff --git a/src/full-codegen.h b/src/full-codegen.h +index d6ed1b9..e3241aa 100644 +--- a/src/full-codegen.h ++++ b/src/full-codegen.h +@@ -505,6 +505,7 @@ class FullCodeGenerator: public AstVisitor { + StrictModeFlag strict_mode_flag() { + return is_strict_mode() ? kStrictMode : kNonStrictMode; + } ++ bool is_qml_mode() { return function()->qml_mode(); } + FunctionLiteral* function() { return info_->function(); } + Scope* scope() { return info_->scope(); } + +diff --git a/src/heap.cc b/src/heap.cc +index 46df787..6e02262 100644 +--- a/src/heap.cc ++++ b/src/heap.cc +@@ -3792,6 +3792,7 @@ MaybeObject* Heap::AllocateFunctionContext(int length, JSFunction* function) { + context->set_previous(NULL); + context->set_extension(NULL); + context->set_global(function->context()->global()); ++ context->set_qml_global(function->context()->qml_global()); + ASSERT(!context->IsGlobalContext()); + ASSERT(context->is_function_context()); + ASSERT(result->IsContext()); +@@ -3814,6 +3815,7 @@ MaybeObject* Heap::AllocateWithContext(Context* previous, + context->set_previous(previous); + context->set_extension(extension); + context->set_global(previous->global()); ++ context->set_qml_global(previous->qml_global()); + ASSERT(!context->IsGlobalContext()); + ASSERT(!context->is_function_context()); + ASSERT(result->IsContext()); +diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc +index 5d32095..afa599e 100644 +--- a/src/ia32/code-stubs-ia32.cc ++++ b/src/ia32/code-stubs-ia32.cc +@@ -147,6 +147,13 @@ void FastNewContextStub::Generate(MacroAssembler* masm) { + __ mov(ebx, Operand(ebx, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_INDEX)), ebx); + ++ // Copy the qml global object from the surrounding context. We go through the ++ // context in the function (ecx) to match the allocation behavior we have ++ // in the runtime system (see Heap::AllocateFunctionContext). ++ __ mov(ebx, FieldOperand(ecx, JSFunction::kContextOffset)); ++ __ mov(ebx, Operand(ebx, 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++) { +diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc +index 5d153a8..28b78ba 100644 +--- a/src/ia32/full-codegen-ia32.cc ++++ b/src/ia32/full-codegen-ia32.cc +@@ -1107,10 +1107,10 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( + + // All extension objects were empty and it is safe to use a global + // load IC call. +- __ mov(eax, GlobalObjectOperand()); ++ __ mov(eax, slot->var()->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); + __ mov(ecx, slot->var()->name()); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); +- RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) ++ RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF || slot->var()->is_qml_global()) + ? RelocInfo::CODE_TARGET + : RelocInfo::CODE_TARGET_CONTEXT; + EmitCallIC(ic, mode); +@@ -1214,10 +1214,10 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) { + Comment cmnt(masm_, "Global variable"); + // Use inline caching. Variable name is passed in ecx and the global + // object on the stack. +- __ mov(eax, GlobalObjectOperand()); ++ __ mov(eax, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); + __ mov(ecx, var->name()); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); +- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); ++ EmitCallIC(ic, var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT); + context()->Plug(eax); + + } else if (slot != NULL && slot->type() == Slot::LOOKUP) { +@@ -1837,11 +1837,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, + // assignment. Right-hand-side value is passed in eax, variable name in + // ecx, and the global object on the stack. + __ mov(ecx, var->name()); +- __ mov(edx, GlobalObjectOperand()); ++ __ mov(edx, var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); + Handle<Code> ic = is_strict_mode() + ? isolate()->builtins()->StoreIC_Initialize_Strict() + : isolate()->builtins()->StoreIC_Initialize(); +- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); ++ EmitCallIC(ic, var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT); + + } else if (op == Token::INIT_CONST) { + // Like var declarations, const declarations are hoisted to function +@@ -2113,9 +2113,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, + // Push the strict mode flag. + __ push(Immediate(Smi::FromInt(strict_mode_flag()))); + ++ // Push the qml mode flag ++ __ push(Immediate(Smi::FromInt(is_qml_mode()))); ++ + __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP + ? Runtime::kResolvePossiblyDirectEvalNoLookup +- : Runtime::kResolvePossiblyDirectEval, 4); ++ : Runtime::kResolvePossiblyDirectEval, 5); + } + + +@@ -2188,8 +2191,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { + context()->DropAndPlug(1, eax); + } else if (var != NULL && !var->is_this() && var->is_global()) { + // Push global object as receiver for the call IC. +- __ push(GlobalObjectOperand()); +- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); ++ __ push(var->is_qml_global()?QmlGlobalObjectOperand():GlobalObjectOperand()); ++ EmitCallWithIC(expr, var->name(), var->is_qml_global()?RelocInfo::CODE_TARGET:RelocInfo::CODE_TARGET_CONTEXT); + } else if (var != NULL && var->AsSlot() != NULL && + var->AsSlot()->type() == Slot::LOOKUP) { + // Call to a lookup slot (dynamically introduced variable). +diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h +index b986264..f8479ae 100644 +--- a/src/ia32/macro-assembler-ia32.h ++++ b/src/ia32/macro-assembler-ia32.h +@@ -778,6 +778,11 @@ static inline Operand GlobalObjectOperand() { + } + + ++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/objects-inl.h b/src/objects-inl.h +index a205f02..8c0c2d0 100644 +--- a/src/objects-inl.h ++++ b/src/objects-inl.h +@@ -3241,6 +3241,18 @@ void SharedFunctionInfo::set_strict_mode(bool value) { + } + + ++bool SharedFunctionInfo::qml_mode() { ++ return BooleanBit::get(compiler_hints(), kQmlModeFunction); ++} ++ ++ ++void SharedFunctionInfo::set_qml_mode(bool value) { ++ set_compiler_hints(BooleanBit::set(compiler_hints(), ++ kQmlModeFunction, ++ value)); ++} ++ ++ + ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset) + ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset) + +diff --git a/src/objects.h b/src/objects.h +index 61685cc..f6549be 100644 +--- a/src/objects.h ++++ b/src/objects.h +@@ -4331,6 +4331,10 @@ class SharedFunctionInfo: public HeapObject { + inline bool strict_mode(); + inline void set_strict_mode(bool value); + ++ // Indicates whether the function is a qml mode function ++ inline bool qml_mode(); ++ inline void set_qml_mode(bool value); ++ + // Indicates whether or not the code in the shared function support + // deoptimization. + inline bool has_deoptimization_support(); +@@ -4511,6 +4515,7 @@ class SharedFunctionInfo: public HeapObject { + static const int kCodeAgeMask = 0x7; + static const int kOptimizationDisabled = 6; + static const int kStrictModeFunction = 7; ++ static const int kQmlModeFunction = 8; + + private: + #if V8_HOST_ARCH_32_BIT +diff --git a/src/parser.cc b/src/parser.cc +index a84ec6f..7f5c361 100644 +--- a/src/parser.cc ++++ b/src/parser.cc +@@ -593,7 +593,8 @@ Parser::Parser(Handle<Script> script, + + FunctionLiteral* Parser::ParseProgram(Handle<String> source, + bool in_global_context, +- StrictModeFlag strict_mode) { ++ StrictModeFlag strict_mode, ++ bool qml_mode) { + CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT); + + HistogramTimerScope timer(isolate()->counters()->parse()); +@@ -609,11 +610,11 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source, + ExternalTwoByteStringUC16CharacterStream stream( + Handle<ExternalTwoByteString>::cast(source), 0, source->length()); + scanner_.Initialize(&stream); +- return DoParseProgram(source, in_global_context, strict_mode, &zone_scope); ++ return DoParseProgram(source, in_global_context, strict_mode, qml_mode, &zone_scope); + } else { + GenericStringUC16CharacterStream stream(source, 0, source->length()); + scanner_.Initialize(&stream); +- return DoParseProgram(source, in_global_context, strict_mode, &zone_scope); ++ return DoParseProgram(source, in_global_context, strict_mode, qml_mode, &zone_scope); + } + } + +@@ -621,6 +622,7 @@ FunctionLiteral* Parser::ParseProgram(Handle<String> source, + FunctionLiteral* Parser::DoParseProgram(Handle<String> source, + bool in_global_context, + StrictModeFlag strict_mode, ++ bool qml_mode, + ZoneScope* zone_scope) { + ASSERT(target_stack_ == NULL); + if (pre_data_ != NULL) pre_data_->Initialize(); +@@ -641,6 +643,9 @@ FunctionLiteral* Parser::DoParseProgram(Handle<String> source, + if (strict_mode == kStrictMode) { + top_scope_->EnableStrictMode(); + } ++ if (qml_mode) { ++ scope->EnableQmlMode(); ++ } + ZoneList<Statement*>* body = new ZoneList<Statement*>(16); + bool ok = true; + int beg_loc = scanner().location().beg_pos; +@@ -729,6 +734,9 @@ FunctionLiteral* Parser::ParseLazy(CompilationInfo* info, + if (shared_info->strict_mode()) { + top_scope_->EnableStrictMode(); + } ++ if (shared_info->qml_mode()) { ++ top_scope_->EnableQmlMode(); ++ } + + FunctionLiteralType type = + shared_info->is_expression() ? EXPRESSION : DECLARATION; +@@ -1661,6 +1669,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, + 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(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 +@@ -1676,6 +1689,11 @@ Block* Parser::ParseVariableDeclarations(bool accept_IN, + arguments->Add(NewNumberLiteral( + top_scope_->is_strict_mode() ? kStrictMode : kNonStrictMode)); + ++ int qml_mode = 0; ++ if (top_scope_->is_qml_mode() && !Isolate::Current()->global()->HasProperty(*name)) ++ qml_mode = 1; ++ arguments->Add(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, +@@ -5157,7 +5175,8 @@ bool ParserApi::Parse(CompilationInfo* info) { + Handle<String> source = Handle<String>(String::cast(script->source())); + result = parser.ParseProgram(source, + info->is_global(), +- info->StrictMode()); ++ info->StrictMode(), ++ info->is_qml_mode()); + } + } + +diff --git a/src/parser.h b/src/parser.h +index 64f1303..4d45e45 100644 +--- a/src/parser.h ++++ b/src/parser.h +@@ -431,7 +431,8 @@ class Parser { + // Returns NULL if parsing failed. + FunctionLiteral* ParseProgram(Handle<String> source, + bool in_global_context, +- StrictModeFlag strict_mode); ++ StrictModeFlag strict_mode, ++ bool qml_mode); + + FunctionLiteral* ParseLazy(CompilationInfo* info); + +@@ -464,6 +465,7 @@ class Parser { + FunctionLiteral* DoParseProgram(Handle<String> source, + bool in_global_context, + StrictModeFlag strict_mode, ++ bool qml_mode, + ZoneScope* zone_scope); + + // Report syntax error +diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc +index c777ab4..1964e02 100644 +--- a/src/prettyprinter.cc ++++ b/src/prettyprinter.cc +@@ -656,6 +656,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/runtime.cc b/src/runtime.cc +index 660352c..827d954 100644 +--- a/src/runtime.cc ++++ b/src/runtime.cc +@@ -1065,8 +1065,6 @@ static Failure* ThrowRedeclarationError(Isolate* isolate, + RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + ASSERT(args.length() == 4); + HandleScope scope(isolate); +- Handle<GlobalObject> global = Handle<GlobalObject>( +- isolate->context()->global()); + + Handle<Context> context = args.at<Context>(0); + CONVERT_ARG_CHECKED(FixedArray, pairs, 1); +@@ -1075,6 +1073,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + static_cast<StrictModeFlag>(Smi::cast(args[3])->value()); + ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode); + ++ Handle<JSObject> js_global = Handle<JSObject>(isolate->context()->global()); ++ Handle<JSObject> qml_global = Handle<JSObject>(isolate->context()->qml_global()); ++ + // Compute the property attributes. According to ECMA-262, section + // 13, page 71, the property must be read-only and + // non-deletable. However, neither SpiderMonkey nor KJS creates the +@@ -1083,10 +1084,13 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) { + + // 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<Smi> is_qml_global(Smi::cast(pairs->get(i + 2))); ++ ++ Handle<JSObject> global = is_qml_global->value()?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 = +@@ -1316,20 +1320,25 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + NoHandleAllocation nha; + // args[0] == name + // args[1] == strict_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_CHECKED(String, name, 0); +- GlobalObject* global = isolate->context()->global(); + RUNTIME_ASSERT(args[1]->IsSmi()); + StrictModeFlag strict_mode = + static_cast<StrictModeFlag>(Smi::cast(args[1])->value()); + ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode); + ++ 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; +@@ -1350,7 +1359,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + if (lookup.IsReadOnly()) { + // If we found readonly property on one of hidden prototypes, + // just shadow it. +- if (real_holder != isolate->context()->global()) break; ++ if (real_holder != global) break; + return ThrowRedeclarationError(isolate, "const", name); + } + +@@ -1372,7 +1381,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + // overwrite it with a variable declaration we must throw a + // re-declaration error. However if we found readonly property + // on one of hidden prototypes, just shadow it. +- if (real_holder != isolate->context()->global()) break; ++ if (real_holder != global) break; + return ThrowRedeclarationError(isolate, "const", name); + } + } +@@ -1384,7 +1393,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + } + + // Assign the value (or undefined) to the property. +- Object* value = (assign) ? args[2] : isolate->heap()->undefined_value(); ++ Object* value = (assign) ? args[3] : isolate->heap()->undefined_value(); + return real_holder->SetProperty( + &lookup, *name, value, attributes, strict_mode); + } +@@ -1399,9 +1408,9 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) { + real_holder = JSObject::cast(proto); + } + +- 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, true); ++ return global->SetProperty(*name, args[3], attributes, strict_mode, true); + } + return isolate->heap()->undefined_value(); + } +@@ -1411,12 +1420,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_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. +@@ -1456,7 +1468,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) { + // with setting the value because the property is either absent or + // read-only. We also have to do redo the lookup. + 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 +@@ -8160,7 +8172,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { + Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source, + context, + true, +- kNonStrictMode); ++ kNonStrictMode, ++ false); + if (shared.is_null()) return Failure::Exception(); + Handle<JSFunction> fun = + isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, +@@ -8173,14 +8186,16 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) { + static ObjectPair CompileGlobalEval(Isolate* isolate, + Handle<String> source, + Handle<Object> receiver, +- StrictModeFlag strict_mode) { ++ StrictModeFlag strict_mode, ++ bool qml_mode) { + // Deal with a normal eval call with a string argument. Compile it + // and return the compiled function bound in the local context. + Handle<SharedFunctionInfo> shared = Compiler::CompileEval( + source, + Handle<Context>(isolate->context()), + isolate->context()->IsGlobalContext(), +- strict_mode); ++ strict_mode, ++ qml_mode); + if (shared.is_null()) return MakePair(Failure::Exception(), NULL); + Handle<JSFunction> compiled = + isolate->factory()->NewFunctionFromSharedFunctionInfo( +@@ -8190,7 +8205,7 @@ static ObjectPair CompileGlobalEval(Isolate* isolate, + + + RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { +- ASSERT(args.length() == 4); ++ ASSERT(args.length() == 5); + + HandleScope scope(isolate); + Handle<Object> callee = args.at<Object>(0); +@@ -8257,16 +8272,18 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) { + } + + ASSERT(args[3]->IsSmi()); ++ ASSERT(args[4]->IsSmi()); + return CompileGlobalEval(isolate, + args.at<String>(1), + args.at<Object>(2), + static_cast<StrictModeFlag>( +- Smi::cast(args[3])->value())); ++ Smi::cast(args[3])->value()), ++ Smi::cast(args[4])->value()); + } + + + RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) { +- ASSERT(args.length() == 4); ++ ASSERT(args.length() == 5); + + HandleScope scope(isolate); + Handle<Object> callee = args.at<Object>(0); +@@ -8280,11 +8297,13 @@ RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) { + } + + ASSERT(args[3]->IsSmi()); ++ ASSERT(args[4]->IsSmi()); + return CompileGlobalEval(isolate, + args.at<String>(1), + args.at<Object>(2), + static_cast<StrictModeFlag>( +- Smi::cast(args[3])->value())); ++ Smi::cast(args[3])->value()), ++ Smi::cast(args[4])->value()); + } + + +@@ -10633,7 +10652,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) { + Compiler::CompileEval(function_source, + context, + context->IsGlobalContext(), +- kNonStrictMode); ++ kNonStrictMode, ++ false); + if (shared.is_null()) return Failure::Exception(); + Handle<JSFunction> compiled_function = + isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context); +@@ -10722,7 +10742,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) { + // Currently, the eval code will be executed in non-strict mode, + // even in the strict code context. + Handle<SharedFunctionInfo> shared = +- Compiler::CompileEval(source, context, is_global, kNonStrictMode); ++ Compiler::CompileEval(source, context, is_global, kNonStrictMode, false); + if (shared.is_null()) return Failure::Exception(); + Handle<JSFunction> compiled_function = + Handle<JSFunction>( +diff --git a/src/runtime.h b/src/runtime.h +index bf1ba68..5e97173 100644 +--- a/src/runtime.h ++++ b/src/runtime.h +@@ -241,8 +241,8 @@ namespace internal { + \ + /* Eval */ \ + F(GlobalReceiver, 1, 1) \ +- F(ResolvePossiblyDirectEval, 4, 2) \ +- F(ResolvePossiblyDirectEvalNoLookup, 4, 2) \ ++ F(ResolvePossiblyDirectEval, 5, 2) \ ++ F(ResolvePossiblyDirectEvalNoLookup, 5, 2) \ + \ + F(SetProperty, -1 /* 4 or 5 */, 1) \ + F(DefineOrRedefineDataProperty, 4, 1) \ +@@ -296,8 +296,8 @@ namespace internal { + /* Declarations and initialization */ \ + F(DeclareGlobals, 4, 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/scopes.cc b/src/scopes.cc +index 8df93c5..e34e762 100644 +--- a/src/scopes.cc ++++ b/src/scopes.cc +@@ -198,6 +198,7 @@ void Scope::SetDefaults(Type type, + scope_calls_eval_ = false; + // Inherit the strict mode from the parent scope. + strict_mode_ = (outer_scope != NULL) && outer_scope->strict_mode_; ++ qml_mode_ = (outer_scope != NULL) && outer_scope->qml_mode_; + outer_scope_calls_eval_ = false; + inner_scope_calls_eval_ = false; + outer_scope_is_eval_scope_ = false; +@@ -516,6 +517,7 @@ bool Scope::HasTrivialContext() const { + if (scope->is_eval_scope()) return false; + if (scope->scope_inside_with_) return false; + if (scope->num_heap_slots_ > 0) return false; ++ if (scope->qml_mode_ && is_global_scope() && inner_scopes_.length()) return false; + } + return true; + } +@@ -796,6 +798,10 @@ void Scope::ResolveVariable(Scope* global_scope, + ASSERT(global_scope != NULL); + var = global_scope->DeclareGlobal(proxy->name()); + ++ if (qml_mode_ && !Isolate::Current()->global()->HasProperty(*(proxy->name()))) { ++ var->set_is_qml_global(true); ++ } ++ + } else if (scope_inside_with_) { + // If we are inside a with statement we give up and look up + // the variable at runtime. +@@ -816,6 +822,8 @@ void Scope::ResolveVariable(Scope* global_scope, + // variables. + if (context->GlobalIfNotShadowedByEval(proxy->name())) { + var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL); ++ if (qml_mode_ && !Isolate::Current()->global()->HasProperty(*(proxy->name()))) ++ var->set_is_qml_global(true); + + } else { + var = NonLocal(proxy->name(), Variable::DYNAMIC); +@@ -827,6 +835,9 @@ void Scope::ResolveVariable(Scope* global_scope, + // variable is global unless it is shadowed by eval-introduced + // variables. + var = NonLocal(proxy->name(), Variable::DYNAMIC_GLOBAL); ++ ++ if (qml_mode_ && !Isolate::Current()->global()->HasProperty(*(proxy->name()))) ++ var->set_is_qml_global(true); + } + } + } +@@ -1112,6 +1123,11 @@ void Scope::AllocateVariablesRecursively() { + must_have_local_context = is_function_scope(); + } + ++ if (qml_mode_ && is_global_scope() && inner_scopes_.length()) { ++ must_have_local_context = true; ++ num_heap_slots_++; // This is a hack to force a context to be allocated to save the QML global ++ } ++ + // If we didn't allocate any locals in the local context, then we only + // need the minimal number of slots if we must have a local context. + if (num_heap_slots_ == Context::MIN_CONTEXT_SLOTS && +diff --git a/src/scopes.h b/src/scopes.h +index a0e56a4..6dd3f65 100644 +--- a/src/scopes.h ++++ b/src/scopes.h +@@ -210,6 +210,11 @@ class Scope: public ZoneObject { + strict_mode_ = FLAG_strict_mode; + } + ++ // Enable qml mode for this scope ++ void EnableQmlMode() { ++ qml_mode_ = true; ++ } ++ + // --------------------------------------------------------------------------- + // Predicates. + +@@ -218,6 +223,7 @@ class Scope: public ZoneObject { + bool is_function_scope() const { return type_ == FUNCTION_SCOPE; } + bool is_global_scope() const { return type_ == GLOBAL_SCOPE; } + bool is_strict_mode() const { return strict_mode_; } ++ bool is_qml_mode() const { return qml_mode_; } + + // Information about which scopes calls eval. + bool calls_eval() const { return scope_calls_eval_; } +@@ -376,6 +382,7 @@ class Scope: public ZoneObject { + bool scope_contains_with_; // this scope contains a 'with' statement + bool scope_calls_eval_; // this scope contains an 'eval' call + bool strict_mode_; // this scope is a strict mode scope ++ bool qml_mode_; // this scope is a qml mode scope + + // Computed via PropagateScopeInfo. + bool outer_scope_calls_eval_; +diff --git a/src/variables.cc b/src/variables.cc +index 0502722..190baf6 100644 +--- a/src/variables.cc ++++ b/src/variables.cc +@@ -99,7 +99,8 @@ Variable::Variable(Scope* scope, + rewrite_(NULL), + is_valid_LHS_(is_valid_LHS), + is_accessed_from_inner_scope_(false), +- is_used_(false) { ++ is_used_(false), ++ is_qml_global_(false) { + // names must be canonicalized for fast equality checks + ASSERT(name->IsSymbol()); + } +diff --git a/src/variables.h b/src/variables.h +index b1ff0db..0b31d1a 100644 +--- a/src/variables.h ++++ b/src/variables.h +@@ -141,6 +141,8 @@ class Variable: public ZoneObject { + Expression* rewrite() const { return rewrite_; } + void set_rewrite(Expression* expr) { rewrite_ = expr; } + ++ 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_; +@@ -159,6 +161,9 @@ class Variable: public ZoneObject { + // Usage info. + bool is_accessed_from_inner_scope_; // set by variable resolver + bool is_used_; ++ ++ // QML info ++ bool is_qml_global_; + }; + + +diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc +index c365385..d923494 100644 +--- a/src/x64/code-stubs-x64.cc ++++ b/src/x64/code-stubs-x64.cc +@@ -140,6 +140,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 qml global object from the surrounding 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++) { +diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc +index 97168cd..342fe9b 100644 +--- a/src/x64/full-codegen-x64.cc ++++ b/src/x64/full-codegen-x64.cc +@@ -1119,10 +1119,10 @@ void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions( + + // All extension objects were empty and it is safe to use a global + // load IC call. +- __ movq(rax, GlobalObjectOperand()); ++ __ movq(rax, slot->var()->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); + __ Move(rcx, slot->var()->name()); + Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize(); +- RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF) ++ RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF || slot->var()->is_qml_global()) + ? RelocInfo::CODE_TARGET + : RelocInfo::CODE_TARGET_CONTEXT; + EmitCallIC(ic, mode); +@@ -1227,9 +1227,9 @@ void FullCodeGenerator::EmitVariableLoad(Variable* var) { + // 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(); +- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); ++ EmitCallIC(ic, var->is_qml_global() ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT); + context()->Plug(rax); + + } else if (slot != NULL && slot->type() == Slot::LOOKUP) { +@@ -1806,11 +1806,11 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var, + // assignment. Right-hand-side value is passed in rax, variable name in + // rcx, and the global object on the stack. + __ Move(rcx, var->name()); +- __ movq(rdx, GlobalObjectOperand()); ++ __ movq(rdx, var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); + Handle<Code> ic = is_strict_mode() + ? isolate()->builtins()->StoreIC_Initialize_Strict() + : isolate()->builtins()->StoreIC_Initialize(); +- EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT); ++ EmitCallIC(ic, var->is_qml_global() ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT); + + } else if (op == Token::INIT_CONST) { + // Like var declarations, const declarations are hoisted to function +@@ -2085,9 +2085,12 @@ void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag, + // Push the strict mode flag. + __ Push(Smi::FromInt(strict_mode_flag())); + ++ // Push the qml mode flag ++ __ Push(Smi::FromInt(is_qml_mode())); ++ + __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP + ? Runtime::kResolvePossiblyDirectEvalNoLookup +- : Runtime::kResolvePossiblyDirectEval, 4); ++ : Runtime::kResolvePossiblyDirectEval, 5); + } + + +@@ -2160,8 +2163,8 @@ void FullCodeGenerator::VisitCall(Call* expr) { + } else if (var != NULL && !var->is_this() && var->is_global()) { + // Call to a global variable. + // Push global object as receiver for the call IC lookup. +- __ push(GlobalObjectOperand()); +- EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); ++ __ push(var->is_qml_global() ? QmlGlobalObjectOperand() : GlobalObjectOperand()); ++ EmitCallWithIC(expr, var->name(), var->is_qml_global() ? RelocInfo::CODE_TARGET : RelocInfo::CODE_TARGET_CONTEXT); + } else if (var != NULL && var->AsSlot() != NULL && + var->AsSlot()->type() == Slot::LOOKUP) { + // Call to a lookup slot (dynamically introduced variable). +diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h +index 4c17720..aa284ed 100644 +--- a/src/x64/macro-assembler-x64.h ++++ b/src/x64/macro-assembler-x64.h +@@ -1233,6 +1233,11 @@ static inline Operand GlobalObjectOperand() { + } + + ++static inline Operand QmlGlobalObjectOperand() { ++ return ContextOperand(rsi, Context::QML_GLOBAL_INDEX); ++} ++ ++ + // Provides access to exit frame stack space (not GCed). + static inline Operand StackSpaceOperand(int index) { + #ifdef _WIN64 +-- +1.7.2.3 + |