Index: src/runtime.cc |
=================================================================== |
--- src/runtime.cc (revision 805) |
+++ src/runtime.cc (working copy) |
@@ -3930,95 +3930,107 @@ |
} |
-static Object* EvalContext() { |
- // The topmost JS frame belongs to the eval function which called |
- // the CompileString runtime function. We need to unwind one level |
- // to get to the caller of eval. |
- StackFrameLocator locator; |
- JavaScriptFrame* frame = locator.FindJavaScriptFrame(1); |
+static Object* Runtime_GlobalReceiver(Arguments args) { |
+ ASSERT(args.length() == 1); |
+ Object* global = args[0]; |
+ if (!global->IsJSGlobalObject()) return Heap::null_value(); |
+ return JSGlobalObject::cast(global)->global_receiver(); |
+} |
- // TODO(900055): Right now we check if the caller of eval() supports |
- // eval to determine if it's an aliased eval or not. This may not be |
- // entirely correct in the unlikely case where a function uses both |
- // aliased and direct eval calls. |
+ |
+static Object* Runtime_CompileString(Arguments args) { |
HandleScope scope; |
- if (!ScopeInfo<>::SupportsEval(frame->FindCode())) { |
- // Aliased eval: Evaluate in the global context of the eval |
- // function to support aliased, cross environment evals. |
- return *Top::global_context(); |
- } |
+ ASSERT(args.length() == 2); |
+ CONVERT_ARG_CHECKED(String, source, 0); |
+ CONVERT_ARG_CHECKED(Smi, line_offset, 1); |
- // Fetch the caller context from the frame. |
- Handle<Context> caller(Context::cast(frame->context())); |
+ // Compile source string. |
+ Handle<JSFunction> boilerplate = |
+ Compiler::CompileEval(source, line_offset->value(), true); |
+ if (boilerplate.is_null()) return Failure::Exception(); |
+ Handle<Context> context(Top::context()->global_context()); |
+ Handle<JSFunction> fun = |
+ Factory::NewFunctionFromBoilerplate(boilerplate, context); |
+ return *fun; |
+} |
- // Check for eval() invocations that cross environments. Use the |
- // context from the stack if evaluating in current environment. |
- Handle<Context> target = Top::global_context(); |
- if (caller->global_context() == *target) return *caller; |
- // Otherwise, use the global context from the other environment. |
- return *target; |
-} |
+static Object* Runtime_ExecDirectEval(Arguments args) { |
+ ASSERT(args.length() == 1); |
+ if (!args[0]->IsString()) return args[0]; |
-static Object* Runtime_EvalReceiver(Arguments args) { |
- ASSERT(args.length() == 1); |
+ Handle<String> source = args.at<String>(0); |
+ |
+ // Compute the eval context. |
+ HandleScope scope; |
StackFrameLocator locator; |
JavaScriptFrame* frame = locator.FindJavaScriptFrame(1); |
- // Fetch the caller context from the frame. |
- Context* caller = Context::cast(frame->context()); |
+ Handle<Context> context(Context::cast(frame->context())); |
+ bool is_global = context->IsGlobalContext(); |
- // Check for eval() invocations that cross environments. Use the |
- // top frames receiver if evaluating in current environment. |
- Context* global_context = Top::context()->global()->global_context(); |
- if (caller->global_context() == global_context) { |
- return frame->receiver(); |
+ // Compile source string. |
+ Handle<JSFunction> boilerplate = |
+ Compiler::CompileEval(source, 0, is_global); |
+ if (boilerplate.is_null()) return Failure::Exception(); |
+ Handle<JSFunction> fun = |
+ Factory::NewFunctionFromBoilerplate(boilerplate, context); |
+ |
+ // Call generated function |
+ Handle<Object> receiver(frame->receiver()); |
+ bool has_pending_exception = false; |
+ Handle<Object> result = |
+ Execution::Call(fun, receiver, 0, NULL, &has_pending_exception); |
+ if (has_pending_exception) { |
+ ASSERT(Top::has_pending_exception()); |
+ return Failure::Exception(); |
} |
+ return *result; |
+} |
- // Otherwise use the given argument (the global object of the |
- // receiving context). |
- return args[0]; |
+ |
+static Object* Runtime_SetInPotentiallyDirectEval(Arguments args) { |
+ ASSERT(args.length() == 0); |
+ Top::set_in_potentially_direct_eval(true); |
+ return Heap::undefined_value(); |
} |
-static Object* Runtime_GlobalReceiver(Arguments args) { |
- ASSERT(args.length() == 1); |
- Object* global = args[0]; |
- if (!global->IsJSGlobalObject()) return Heap::null_value(); |
- return JSGlobalObject::cast(global)->global_receiver(); |
+static Object* Runtime_ClearInPotentiallyDirectEval(Arguments args) { |
+ ASSERT(args.length() == 0); |
+ Top::set_in_potentially_direct_eval(false); |
+ return Heap::undefined_value(); |
} |
-static Object* Runtime_CompileString(Arguments args) { |
- HandleScope scope; |
- ASSERT(args.length() == 3); |
- CONVERT_ARG_CHECKED(String, source, 0); |
- CONVERT_ARG_CHECKED(Smi, line_offset, 1); |
- bool contextual = args[2]->IsTrue(); |
- RUNTIME_ASSERT(contextual || args[2]->IsFalse()); |
+static Object* Runtime_InDirectEval(Arguments args) { |
+ ASSERT(args.length() == 0); |
- // Compute the eval context. |
- Handle<Context> context; |
- if (contextual) { |
- // Get eval context. May not be available if we are calling eval |
- // through an alias, and the corresponding frame doesn't have a |
- // proper eval context set up. |
- Object* eval_context = EvalContext(); |
- if (eval_context->IsFailure()) return eval_context; |
- context = Handle<Context>(Context::cast(eval_context)); |
- } else { |
- context = Handle<Context>(Top::context()->global_context()); |
+ // No need to look further if the static analysis showed that this |
+ // is aliased. |
+ if (!Top::is_in_potentially_direct_eval()) { |
+ return Heap::false_value(); |
} |
- |
- // Compile source string. |
- bool is_global = context->IsGlobalContext(); |
- Handle<JSFunction> boilerplate = |
- Compiler::CompileEval(source, line_offset->value(), is_global); |
- if (boilerplate.is_null()) return Failure::Exception(); |
- Handle<JSFunction> fun = |
- Factory::NewFunctionFromBoilerplate(boilerplate, context); |
- return *fun; |
+ // Find where the 'eval' symbol is bound. It is unaliased only if |
+ // it is bound in the global object. |
+ HandleScope scope; |
+ StackFrameLocator locator; |
+ JavaScriptFrame* frame = locator.FindJavaScriptFrame(1); |
+ Context* context = Context::cast(frame->context()); |
+ int index; |
+ PropertyAttributes attributes; |
+ while (context && !context->IsGlobalContext()) { |
+ context->Lookup(Factory::eval_symbol(), FOLLOW_PROTOTYPE_CHAIN, |
+ &index, &attributes); |
+ if (attributes != ABSENT) return Heap::false_value(); |
+ if (context->is_function_context()) { |
+ context = Context::cast(context->closure()->context()); |
+ } else { |
+ context = context->previous(); |
+ } |
+ } |
+ return Heap::true_value(); |
} |