__ ldr(r1, frame_->Receiver());
frame_->EmitPush(r1);
- frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 3);
+ // Push the strict mode flag.
+ frame_->EmitPush(Operand(Smi::FromInt(strict_mode_flag())));
+
+ frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 4);
done.Jump();
slow.Bind();
__ ldr(r1, frame_->Receiver());
frame_->EmitPush(r1);
+ // Push the strict mode flag.
+ frame_->EmitPush(Operand(Smi::FromInt(strict_mode_flag())));
+
// Resolve the call.
- frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+ frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 4);
// If we generated fast-case code bind the jump-target where fast
// and slow case merge.
// Accessors
inline bool is_eval();
inline Scope* scope();
+ inline StrictModeFlag strict_mode_flag();
// Generating deferred code.
void ProcessDeferred();
__ ldr(r1,
MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
__ push(r1);
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+ // Push the strict mode flag.
+ __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
+ __ push(r1);
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4);
// The runtime call returns a pair of values in r0 (function) and
// r1 (receiver). Touch up the stack with the right values.
Scope* CodeGenerator::scope() { return info_->function()->scope(); }
+StrictModeFlag CodeGenerator::strict_mode_flag() {
+ return info_->function()->strict_mode() ? kStrictMode : kNonStrictMode;
+}
+
} } // namespace v8::internal
#endif // V8_CODEGEN_INL_H_
: CompilationSubCache(generations) { }
Handle<SharedFunctionInfo> Lookup(Handle<String> source,
- Handle<Context> context);
+ Handle<Context> context,
+ StrictModeFlag strict_mode);
void Put(Handle<String> source,
Handle<Context> context,
Handle<SharedFunctionInfo> CompilationCacheEval::Lookup(
- Handle<String> source, Handle<Context> context) {
+ Handle<String> source,
+ Handle<Context> context,
+ StrictModeFlag strict_mode) {
// Make sure not to leak the table into the surrounding handle
// scope. Otherwise, we risk keeping old tables around even after
// having cleared the cache.
{ HandleScope scope;
for (generation = 0; generation < generations(); generation++) {
Handle<CompilationCacheTable> table = GetTable(generation);
- result = table->LookupEval(*source, *context);
+ result = table->LookupEval(*source, *context, strict_mode);
if (result->IsSharedFunctionInfo()) {
break;
}
}
-Handle<SharedFunctionInfo> CompilationCache::LookupEval(Handle<String> source,
- Handle<Context> context,
- bool is_global) {
+Handle<SharedFunctionInfo> CompilationCache::LookupEval(
+ Handle<String> source,
+ Handle<Context> context,
+ bool is_global,
+ StrictModeFlag strict_mode) {
if (!IsEnabled()) {
return Handle<SharedFunctionInfo>::null();
}
Handle<SharedFunctionInfo> result;
if (is_global) {
- result = eval_global.Lookup(source, context);
+ result = eval_global.Lookup(source, context, strict_mode);
} else {
- result = eval_contextual.Lookup(source, context);
+ result = eval_contextual.Lookup(source, context, strict_mode);
}
return result;
}
// contain a script for the given source string.
static Handle<SharedFunctionInfo> LookupEval(Handle<String> source,
Handle<Context> context,
- bool is_global);
+ bool is_global,
+ StrictModeFlag strict_mode);
// Returns the regexp data associated with the given regexp if it
// is in cache, otherwise an empty handle.
Handle<SharedFunctionInfo> Compiler::CompileEval(Handle<String> source,
Handle<Context> context,
- bool is_global) {
+ bool is_global,
+ StrictModeFlag strict_mode) {
int source_length = source->length();
Counters::total_eval_size.Increment(source_length);
Counters::total_compile_size.Increment(source_length);
// Do a lookup in the compilation cache; if the entry is not there, invoke
// the compiler and add the result to the cache.
Handle<SharedFunctionInfo> result;
- result = CompilationCache::LookupEval(source, context, is_global);
+ result = CompilationCache::LookupEval(source,
+ context,
+ is_global,
+ strict_mode);
if (result.is_null()) {
// Create a script object describing the script to be compiled.
CompilationInfo info(script);
info.MarkAsEval();
if (is_global) info.MarkAsGlobal();
+ if (strict_mode == kStrictMode) info.MarkAsStrict();
info.SetCallingContext(context);
result = MakeFunctionInfo(&info);
if (!result.is_null()) {
+ // If caller is strict mode, the result must be strict as well,
+ // but not the other way around. Consider:
+ // eval("'use strict'; ...");
+ ASSERT(strict_mode == kNonStrictMode || result->strict_mode());
CompilationCache::PutEval(source, context, is_global, result);
}
}
*lit->this_property_assignments());
function_info->set_try_full_codegen(lit->try_full_codegen());
function_info->set_allows_lazy_compilation(lit->AllowsLazyCompilation());
+ function_info->set_strict_mode(lit->strict_mode());
}
bool is_lazy() const { return (flags_ & IsLazy::mask()) != 0; }
bool is_eval() const { return (flags_ & IsEval::mask()) != 0; }
bool is_global() const { return (flags_ & IsGlobal::mask()) != 0; }
+ bool is_strict() const { return (flags_ & IsStrict::mask()) != 0; }
bool is_in_loop() const { return (flags_ & IsInLoop::mask()) != 0; }
FunctionLiteral* function() const { return function_; }
Scope* scope() const { return scope_; }
ASSERT(!is_lazy());
flags_ |= IsGlobal::encode(true);
}
+ void MarkAsStrict() {
+ ASSERT(!is_lazy());
+ flags_ |= IsStrict::encode(true);
+ }
+ StrictModeFlag StrictMode() {
+ return is_strict() ? kStrictMode : kNonStrictMode;
+ }
void MarkAsInLoop() {
ASSERT(is_lazy());
flags_ |= IsInLoop::encode(true);
class IsGlobal: public BitField<bool, 2, 1> {};
// Flags that can be set for lazy compilation.
class IsInLoop: public BitField<bool, 3, 1> {};
+ // Strict mode - used in eager compilation.
+ class IsStrict: public BitField<bool, 4, 1> {};
unsigned flags_;
// Compile a String source within a context for Eval.
static Handle<SharedFunctionInfo> CompileEval(Handle<String> source,
Handle<Context> context,
- bool is_global);
+ bool is_global,
+ StrictModeFlag strict_mode);
// Compile from function info (used for lazy compilation). Returns true on
// success and false if the compilation resulted in a stack overflow.
Handle<Script> script() { return info_->script(); }
bool is_eval() { return info_->is_eval(); }
+ StrictModeFlag strict_mode_flag() {
+ return function()->strict_mode() ? kStrictMode : kNonStrictMode;
+ }
FunctionLiteral* function() { return info_->function(); }
Scope* scope() { return info_->scope(); }
}
frame_->PushParameterAt(-1);
+ // Push the strict mode flag.
+ frame_->Push(Smi::FromInt(strict_mode_flag()));
+
// Resolve the call.
result =
- frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 3);
+ frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 4);
done.Jump(&result);
slow.Bind();
}
frame_->PushParameterAt(-1);
+ // Push the strict mode flag.
+ frame_->Push(Smi::FromInt(strict_mode_flag()));
+
// Resolve the call.
- result = frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+ result = frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 4);
// If we generated fast-case code bind the jump-target where fast
// and slow case merge.
// Accessors
inline bool is_eval();
inline Scope* scope();
+ inline StrictModeFlag strict_mode_flag();
// Generating deferred code.
void ProcessDeferred();
// Push the receiver of the enclosing function and do runtime call.
__ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+ // Push the strict mode flag.
+ __ push(Immediate(Smi::FromInt(strict_mode_flag())));
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4);
// The runtime call returns a pair of values in eax (function) and
// edx (receiver). Touch up the stack with the right values.
}
+bool SharedFunctionInfo::strict_mode() {
+ return BooleanBit::get(compiler_hints(), kStrictModeFunction);
+}
+
+
+void SharedFunctionInfo::set_strict_mode(bool value) {
+ set_compiler_hints(BooleanBit::set(compiler_hints(),
+ kStrictModeFunction,
+ value));
+}
+
+
ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset)
// StringSharedKeys are used as keys in the eval cache.
class StringSharedKey : public HashTableKey {
public:
- StringSharedKey(String* source, SharedFunctionInfo* shared)
- : source_(source), shared_(shared) { }
+ StringSharedKey(String* source,
+ SharedFunctionInfo* shared,
+ StrictModeFlag strict_mode)
+ : source_(source),
+ shared_(shared),
+ strict_mode_(strict_mode) { }
bool IsMatch(Object* other) {
if (!other->IsFixedArray()) return false;
FixedArray* pair = FixedArray::cast(other);
SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
if (shared != shared_) return false;
+ StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
+ Smi::cast(pair->get(2))->value());
+ if (strict_mode != strict_mode_) return false;
String* source = String::cast(pair->get(1));
return source->Equals(source_);
}
static uint32_t StringSharedHashHelper(String* source,
- SharedFunctionInfo* shared) {
+ SharedFunctionInfo* shared,
+ StrictModeFlag strict_mode) {
uint32_t hash = source->Hash();
if (shared->HasSourceCode()) {
// Instead of using the SharedFunctionInfo pointer in the hash
// collection.
Script* script = Script::cast(shared->script());
hash ^= String::cast(script->source())->Hash();
+ if (strict_mode == kStrictMode) hash ^= 0x8000;
hash += shared->start_position();
}
return hash;
}
uint32_t Hash() {
- return StringSharedHashHelper(source_, shared_);
+ return StringSharedHashHelper(source_, shared_, strict_mode_);
}
uint32_t HashForObject(Object* obj) {
FixedArray* pair = FixedArray::cast(obj);
SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
String* source = String::cast(pair->get(1));
- return StringSharedHashHelper(source, shared);
+ StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
+ Smi::cast(pair->get(2))->value());
+ return StringSharedHashHelper(source, shared, strict_mode);
}
MUST_USE_RESULT MaybeObject* AsObject() {
Object* obj;
- { MaybeObject* maybe_obj = Heap::AllocateFixedArray(2);
+ { MaybeObject* maybe_obj = Heap::AllocateFixedArray(3);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
FixedArray* pair = FixedArray::cast(obj);
pair->set(0, shared_);
pair->set(1, source_);
+ pair->set(2, Smi::FromInt(strict_mode_));
return pair;
}
private:
String* source_;
SharedFunctionInfo* shared_;
+ StrictModeFlag strict_mode_;
};
}
-Object* CompilationCacheTable::LookupEval(String* src, Context* context) {
- StringSharedKey key(src, context->closure()->shared());
+Object* CompilationCacheTable::LookupEval(String* src,
+ Context* context,
+ StrictModeFlag strict_mode) {
+ StringSharedKey key(src, context->closure()->shared(), strict_mode);
int entry = FindEntry(&key);
if (entry == kNotFound) return Heap::undefined_value();
return get(EntryToIndex(entry) + 1);
MaybeObject* CompilationCacheTable::PutEval(String* src,
Context* context,
- Object* value) {
- StringSharedKey key(src, context->closure()->shared());
+ SharedFunctionInfo* value) {
+ StringSharedKey key(src,
+ context->closure()->shared(),
+ value->strict_mode() ? kStrictMode : kNonStrictMode);
Object* obj;
{ MaybeObject* maybe_obj = EnsureCapacity(1, &key);
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
inline bool optimization_disabled();
inline void set_optimization_disabled(bool value);
+ // Indicates whether the function is a strict mode function.
+ inline bool strict_mode();
+ inline void set_strict_mode(bool value);
+
// Indicates whether or not the code in the shared function support
// deoptimization.
inline bool has_deoptimization_support();
static const int kCodeAgeShift = 4;
static const int kCodeAgeMask = 0x7;
static const int kOptimizationDisabled = 7;
+ static const int kStrictModeFunction = 8;
DISALLOW_IMPLICIT_CONSTRUCTORS(SharedFunctionInfo);
};
public:
// Find cached value for a string key, otherwise return null.
Object* Lookup(String* src);
- Object* LookupEval(String* src, Context* context);
+ Object* LookupEval(String* src, Context* context, StrictModeFlag strict_mode);
Object* LookupRegExp(String* source, JSRegExp::Flags flags);
MaybeObject* Put(String* src, Object* value);
- MaybeObject* PutEval(String* src, Context* context, Object* value);
+ MaybeObject* PutEval(String* src,
+ Context* context,
+ SharedFunctionInfo* value);
MaybeObject* PutRegExp(String* src, JSRegExp::Flags flags, FixedArray* value);
// Remove given value from cache.
FunctionLiteral* Parser::ParseProgram(Handle<String> source,
- bool in_global_context) {
+ bool in_global_context,
+ StrictModeFlag strict_mode) {
CompilationZoneScope zone_scope(DONT_DELETE_ON_EXIT);
HistogramTimerScope timer(&Counters::parse);
ExternalTwoByteStringUC16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length());
scanner_.Initialize(&stream);
- return DoParseProgram(source, in_global_context, &zone_scope);
+ return DoParseProgram(source, in_global_context, strict_mode, &zone_scope);
} else {
GenericStringUC16CharacterStream stream(source, 0, source->length());
scanner_.Initialize(&stream);
- return DoParseProgram(source, in_global_context, &zone_scope);
+ return DoParseProgram(source, in_global_context, strict_mode, &zone_scope);
}
}
FunctionLiteral* Parser::DoParseProgram(Handle<String> source,
bool in_global_context,
+ StrictModeFlag strict_mode,
ZoneScope* zone_scope) {
ASSERT(target_stack_ == NULL);
if (pre_data_ != NULL) pre_data_->Initialize();
LexicalScope lexical_scope(&this->top_scope_, &this->with_nesting_level_,
scope);
TemporaryScope temp_scope(&this->temp_scope_);
+ if (strict_mode == kStrictMode) {
+ temp_scope.EnableStrictMode();
+ }
ZoneList<Statement*>* body = new ZoneList<Statement*>(16);
bool ok = true;
int beg_loc = scanner().location().beg_pos;
scope);
TemporaryScope temp_scope(&this->temp_scope_);
+ if (info->strict_mode()) {
+ temp_scope.EnableStrictMode();
+ }
+
FunctionLiteralType type =
info->is_expression() ? EXPRESSION : DECLARATION;
bool ok = true;
ASSERT(Top::has_pending_exception());
} else {
Handle<String> source = Handle<String>(String::cast(script->source()));
- result = parser.ParseProgram(source, info->is_global());
+ result = parser.ParseProgram(source,
+ info->is_global(),
+ info->StrictMode());
}
}
// Returns NULL if parsing failed.
FunctionLiteral* ParseProgram(Handle<String> source,
- bool in_global_context);
+ bool in_global_context,
+ StrictModeFlag strict_mode);
FunctionLiteral* ParseLazy(Handle<SharedFunctionInfo> info);
// Called by ParseProgram after setting up the scanner.
FunctionLiteral* DoParseProgram(Handle<String> source,
bool in_global_context,
+ StrictModeFlag strict_mode,
ZoneScope* zone_scope);
// Report syntax error
Handle<Context> context(Top::context()->global_context());
Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
context,
- true);
+ true,
+ kNonStrictMode);
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> fun =
Factory::NewFunctionFromSharedFunctionInfo(shared, context, NOT_TENURED);
static ObjectPair CompileGlobalEval(Handle<String> source,
- Handle<Object> receiver) {
+ Handle<Object> receiver,
+ StrictModeFlag 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>(Top::context()),
- Top::context()->IsGlobalContext());
+ Top::context()->IsGlobalContext(),
+ mode);
if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
Handle<JSFunction> compiled = Factory::NewFunctionFromSharedFunctionInfo(
shared,
static ObjectPair Runtime_ResolvePossiblyDirectEval(Arguments args) {
- ASSERT(args.length() == 3);
+ ASSERT(args.length() == 4);
if (!args[0]->IsJSFunction()) {
return MakePair(Top::ThrowIllegalOperation(), NULL);
}
return MakePair(*callee, Top::context()->global()->global_receiver());
}
- return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
+ ASSERT(args[3]->IsSmi());
+ return CompileGlobalEval(args.at<String>(1),
+ args.at<Object>(2),
+ static_cast<StrictModeFlag>(
+ Smi::cast(args[3])->value()));
}
static ObjectPair Runtime_ResolvePossiblyDirectEvalNoLookup(Arguments args) {
- ASSERT(args.length() == 3);
+ ASSERT(args.length() == 4);
if (!args[0]->IsJSFunction()) {
return MakePair(Top::ThrowIllegalOperation(), NULL);
}
return MakePair(*callee, Top::context()->global()->global_receiver());
}
- return CompileGlobalEval(args.at<String>(1), args.at<Object>(2));
+ ASSERT(args[3]->IsSmi());
+ return CompileGlobalEval(args.at<String>(1),
+ args.at<Object>(2),
+ static_cast<StrictModeFlag>(
+ Smi::cast(args[3])->value()));
}
Handle<String> function_source =
Factory::NewStringFromAscii(Vector<const char>(source_str,
source_str_length));
+
+ // Currently, the eval code will be executed in non-strict mode,
+ // even in the strict code context.
Handle<SharedFunctionInfo> shared =
Compiler::CompileEval(function_source,
context,
- context->IsGlobalContext());
+ context->IsGlobalContext(),
+ kNonStrictMode);
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function =
Factory::NewFunctionFromSharedFunctionInfo(shared, context);
}
// Compile the source to be evaluated.
+ // 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);
+ Compiler::CompileEval(source, context, is_global, kNonStrictMode);
if (shared.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function =
Handle<JSFunction>(Factory::NewFunctionFromSharedFunctionInfo(shared,
\
/* Eval */ \
F(GlobalReceiver, 1, 1) \
- F(ResolvePossiblyDirectEval, 3, 2) \
- F(ResolvePossiblyDirectEvalNoLookup, 3, 2) \
+ F(ResolvePossiblyDirectEval, 4, 2) \
+ F(ResolvePossiblyDirectEvalNoLookup, 4, 2) \
\
F(SetProperty, -1 /* 3 or 4 */, 1) \
F(DefineOrRedefineDataProperty, 4, 1) \
ARMv7 = 2, // ARM
SAHF = 0}; // x86
+// The Strict Mode (ECMA-262 5th edition, 4.2.2).
+enum StrictModeFlag {
+ kNonStrictMode,
+ kStrictMode
+};
+
} } // namespace v8::internal
#endif // V8_V8GLOBALS_H_
}
frame_->PushParameterAt(-1);
+ // Push the strict mode flag.
+ frame_->Push(Smi::FromInt(strict_mode_flag()));
+
// Resolve the call.
result =
- frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 3);
+ frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 4);
done.Jump(&result);
slow.Bind();
}
frame_->PushParameterAt(-1);
+ // Push the strict mode flag.
+ frame_->Push(Smi::FromInt(strict_mode_flag()));
+
// Resolve the call.
- result = frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+ result = frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 4);
// If we generated fast-case code bind the jump-target where fast
// and slow case merge.
// Accessors
inline bool is_eval();
inline Scope* scope();
+ inline StrictModeFlag strict_mode_flag();
// Generating deferred code.
void ProcessDeferred();
// Push the receiver of the enclosing function and do runtime call.
__ push(Operand(rbp, (2 + scope()->num_parameters()) * kPointerSize));
- __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
+ // Push the strict mode flag.
+ __ Push(Smi::FromInt(strict_mode_flag()));
+ __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4);
// The runtime call returns a pair of values in rax (function) and
// rdx (receiver). Touch up the stack with the right values.
--- /dev/null
+// Copyright 2011 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"use strict";
+
+var code1 = "function f(eval) {}";
+var code2 = "function f(a, a) {}";
+var code3 = "var x = '\\020;'";
+var code4 = "function arguments() {}";
+
+// Verify the code compiles just fine in non-strict mode
+// (using aliased eval to force non-strict mode)
+var eval_alias = eval;
+
+eval_alias(code1);
+eval_alias(code2);
+eval_alias(code3);
+eval_alias(code4);
+
+function strict1() {
+ try {
+ eval(code1);
+ assertUnreachable("did not throw exception");
+ } catch (e) {
+ assertInstanceof(e, SyntaxError);
+ }
+
+ function strict2() {
+ try {
+ eval(code2);
+ assertUnreachable("did not throw exception");
+ } catch (e) {
+ assertInstanceof(e, SyntaxError);
+ }
+
+ function strict3() {
+ try {
+ eval(code3);
+ assertUnreachable("did not throw exception");
+ } catch (e) {
+ assertInstanceof(e, SyntaxError);
+ }
+
+ function strict4() {
+ try {
+ eval(code4);
+ assertUnreachable("did not throw exception");
+ } catch (e) {
+ assertInstanceof(e, SyntaxError);
+ }
+ }
+ strict4();
+ }
+ strict3();
+ }
+ strict2();
+}
+strict1();