Revision: 7250
Author: [email protected]
Date: Thu Mar 17 13:28:17 2011
Log: Strict mode ThrowTypeError functions for
- function.caller
- function.arguments
Review URL: http://codereview.chromium.org/6694044/
http://code.google.com/p/v8/source/detail?r=7250
Modified:
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/full-codegen-arm.cc
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/bootstrapper.cc
/branches/bleeding_edge/src/builtins.cc
/branches/bleeding_edge/src/builtins.h
/branches/bleeding_edge/src/contexts.h
/branches/bleeding_edge/src/factory.cc
/branches/bleeding_edge/src/factory.h
/branches/bleeding_edge/src/handles.cc
/branches/bleeding_edge/src/handles.h
/branches/bleeding_edge/src/ia32/codegen-ia32.cc
/branches/bleeding_edge/src/ia32/full-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/messages.js
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/x64/codegen-x64.cc
/branches/bleeding_edge/src/x64/full-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
/branches/bleeding_edge/test/mjsunit/strict-mode.js
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Tue Mar 15 14:56:12 2011
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Thu Mar 17 13:28:17 2011
@@ -3114,9 +3114,10 @@
bool pretenure) {
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
- if (scope()->is_function_scope() &&
+ if (!pretenure &&
+ scope()->is_function_scope() &&
function_info->num_literals() == 0 &&
- !pretenure) {
+ !function_info->strict_mode()) { // Strict mode functions use slow
path.
FastNewClosureStub stub;
frame_->EmitPush(Operand(function_info));
frame_->SpillAll();
=======================================
--- /branches/bleeding_edge/src/arm/full-codegen-arm.cc Thu Mar 17 07:30:48
2011
+++ /branches/bleeding_edge/src/arm/full-codegen-arm.cc Thu Mar 17 13:28:17
2011
@@ -1084,9 +1084,10 @@
// doesn't just get a copy of the existing unoptimized code.
if (!FLAG_always_opt &&
!FLAG_prepare_always_opt &&
+ !pretenure &&
scope()->is_function_scope() &&
info->num_literals() == 0 &&
- !pretenure) {
+ !info->strict_mode()) { // Strict mode functions use slow path.
FastNewClosureStub stub;
__ mov(r0, Operand(info));
__ push(r0);
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Thu Mar 17
07:30:48 2011
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Thu Mar 17
13:28:17 2011
@@ -3726,7 +3726,8 @@
// space for nested functions that don't need literals cloning.
Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
- if (shared_info->num_literals() == 0 && !pretenure) {
+ if (!pretenure && shared_info->num_literals() == 0 &&
+ !shared_info->strict_mode()) { // Strict mode functions use slow
path.
FastNewClosureStub stub;
__ mov(r1, Operand(shared_info));
__ push(r1);
=======================================
--- /branches/bleeding_edge/src/bootstrapper.cc Tue Mar 15 04:01:21 2011
+++ /branches/bleeding_edge/src/bootstrapper.cc Thu Mar 17 13:28:17 2011
@@ -207,6 +207,10 @@
void CreateRoots();
// Creates the empty function. Used for creating a context from scratch.
Handle<JSFunction> CreateEmptyFunction();
+ // Creates the ThrowTypeError function. ECMA 5th Ed. 13.2.3
+ Handle<JSFunction> CreateThrowTypeErrorFunction(Builtins::Name builtin);
+
+ void CreateStrictModeFunctionMaps(Handle<JSFunction> empty);
// Creates the global objects using the global and the template passed in
// through the API. We call this regardless of whether we are building a
// context from scratch or using a deserialized one from the partial
snapshot
@@ -260,10 +264,24 @@
ADD_READONLY_PROTOTYPE,
ADD_WRITEABLE_PROTOTYPE
};
+
+ Handle<Map> CreateFunctionMap(PrototypePropertyMode prototype_mode);
+
Handle<DescriptorArray> ComputeFunctionInstanceDescriptor(
PrototypePropertyMode prototypeMode);
void MakeFunctionInstancePrototypeWritable();
+ Handle<Map> CreateStrictModeFunctionMap(
+ PrototypePropertyMode prototype_mode,
+ Handle<JSFunction> empty_function,
+ Handle<FixedArray> arguments_callbacks,
+ Handle<FixedArray> caller_callbacks);
+
+ Handle<DescriptorArray> ComputeStrictFunctionInstanceDescriptor(
+ PrototypePropertyMode propertyMode,
+ Handle<FixedArray> arguments,
+ Handle<FixedArray> caller);
+
static bool CompileBuiltin(int index);
static bool CompileNative(Vector<const char> name, Handle<String>
source);
static bool CompileScriptCached(Vector<const char> name,
@@ -274,7 +292,14 @@
bool use_runtime_context);
Handle<Context> result_;
- Handle<JSFunction> empty_function_;
+
+ // Function instance maps. Function literal maps are created initially
with
+ // a read only prototype for the processing of JS builtins. Later the
function
+ // instance maps are replaced in order to make prototype writable.
+ // These are the final, writable prototype, maps.
+ Handle<Map> function_instance_map_writable_prototype_;
+ Handle<Map> strict_mode_function_instance_map_writable_prototype_;
+
BootstrapperActive active_;
friend class Bootstrapper;
};
@@ -359,89 +384,79 @@
Handle<DescriptorArray> Genesis::ComputeFunctionInstanceDescriptor(
PrototypePropertyMode prototypeMode) {
- Handle<DescriptorArray> result = Factory::empty_descriptor_array();
-
+ Handle<DescriptorArray> descriptors =
+ Factory::NewDescriptorArray(prototypeMode == DONT_ADD_PROTOTYPE ?
4 : 5);
+ PropertyAttributes attributes =
+ static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
+
+ { // Add length.
+ Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionLength);
+ CallbacksDescriptor d(*Factory::length_symbol(), *proxy, attributes);
+ descriptors->Set(0, &d);
+ }
+ { // Add name.
+ Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionName);
+ CallbacksDescriptor d(*Factory::name_symbol(), *proxy, attributes);
+ descriptors->Set(1, &d);
+ }
+ { // Add arguments.
+ Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionArguments);
+ CallbacksDescriptor d(*Factory::arguments_symbol(), *proxy,
attributes);
+ descriptors->Set(2, &d);
+ }
+ { // Add caller.
+ Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionCaller);
+ CallbacksDescriptor d(*Factory::caller_symbol(), *proxy, attributes);
+ descriptors->Set(3, &d);
+ }
if (prototypeMode != DONT_ADD_PROTOTYPE) {
- PropertyAttributes attributes = static_cast<PropertyAttributes>(
- DONT_ENUM |
- DONT_DELETE |
- (prototypeMode == ADD_READONLY_PROTOTYPE ? READ_ONLY : 0));
- result =
- Factory::CopyAppendProxyDescriptor(
- result,
- Factory::prototype_symbol(),
- Factory::NewProxy(&Accessors::FunctionPrototype),
- attributes);
- }
-
- PropertyAttributes attributes =
- static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
- // Add length.
- result =
- Factory::CopyAppendProxyDescriptor(
- result,
- Factory::length_symbol(),
- Factory::NewProxy(&Accessors::FunctionLength),
- attributes);
-
- // Add name.
- result =
- Factory::CopyAppendProxyDescriptor(
- result,
- Factory::name_symbol(),
- Factory::NewProxy(&Accessors::FunctionName),
- attributes);
-
- // Add arguments.
- result =
- Factory::CopyAppendProxyDescriptor(
- result,
- Factory::arguments_symbol(),
- Factory::NewProxy(&Accessors::FunctionArguments),
- attributes);
-
- // Add caller.
- result =
- Factory::CopyAppendProxyDescriptor(
- result,
- Factory::caller_symbol(),
- Factory::NewProxy(&Accessors::FunctionCaller),
- attributes);
-
- return result;
+ // Add prototype.
+ if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
+ attributes = static_cast<PropertyAttributes>(attributes &
~READ_ONLY);
+ }
+ Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionPrototype);
+ CallbacksDescriptor d(*Factory::prototype_symbol(), *proxy,
attributes);
+ descriptors->Set(4, &d);
+ }
+ descriptors->Sort();
+ return descriptors;
+}
+
+
+Handle<Map> Genesis::CreateFunctionMap(PrototypePropertyMode
prototype_mode) {
+ Handle<Map> map = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
+ Handle<DescriptorArray> descriptors =
+ ComputeFunctionInstanceDescriptor(prototype_mode);
+ map->set_instance_descriptors(*descriptors);
+ map->set_function_with_prototype(prototype_mode != DONT_ADD_PROTOTYPE);
+ return map;
}
Handle<JSFunction> Genesis::CreateEmptyFunction() {
- // Allocate the map for function instances.
- Handle<Map> fm = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
- global_context()->set_function_instance_map(*fm);
+ // Allocate the map for function instances. Maps are allocated first and
their
+ // prototypes patched later, once empty function is created.
+
// Please note that the prototype property for function instances must be
// writable.
- Handle<DescriptorArray> function_map_descriptors =
- ComputeFunctionInstanceDescriptor(ADD_WRITEABLE_PROTOTYPE);
- fm->set_instance_descriptors(*function_map_descriptors);
- fm->set_function_with_prototype(true);
+ global_context()->set_function_instance_map(
+ *CreateFunctionMap(ADD_WRITEABLE_PROTOTYPE));
// Functions with this map will not have a 'prototype' property, and
// can not be used as constructors.
- Handle<Map> function_without_prototype_map =
- Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
global_context()->set_function_without_prototype_map(
- *function_without_prototype_map);
- Handle<DescriptorArray> function_without_prototype_map_descriptors =
- ComputeFunctionInstanceDescriptor(DONT_ADD_PROTOTYPE);
- function_without_prototype_map->set_instance_descriptors(
- *function_without_prototype_map_descriptors);
- function_without_prototype_map->set_function_with_prototype(false);
-
- // Allocate the function map first and then patch the prototype later
- fm = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
- global_context()->set_function_map(*fm);
- function_map_descriptors =
- ComputeFunctionInstanceDescriptor(ADD_READONLY_PROTOTYPE);
- fm->set_instance_descriptors(*function_map_descriptors);
- fm->set_function_with_prototype(true);
+ *CreateFunctionMap(DONT_ADD_PROTOTYPE));
+
+ // Allocate the function map. This map is temporary, used only for
processing
+ // of builtins.
+ // Later the map is replaced with writable prototype map, allocated
below.
+ global_context()->set_function_map(
+ *CreateFunctionMap(ADD_READONLY_PROTOTYPE));
+
+ // The final map for functions. Writeable prototype.
+ // This map is installed in MakeFunctionInstancePrototypeWritable.
+ function_instance_map_writable_prototype_ =
+ CreateFunctionMap(ADD_WRITEABLE_PROTOTYPE);
Handle<String> object_name = Handle<String>(Heap::Object_symbol());
@@ -469,7 +484,7 @@
// 262 15.3.4.
Handle<String> symbol = Factory::LookupAsciiSymbol("Empty");
Handle<JSFunction> empty_function =
- Factory::NewFunctionWithoutPrototype(symbol);
+ Factory::NewFunctionWithoutPrototype(symbol, kNonStrictMode);
// --- E m p t y ---
Handle<Code> code =
@@ -483,20 +498,147 @@
empty_function->shared()->set_start_position(0);
empty_function->shared()->set_end_position(source->length());
empty_function->shared()->DontAdaptArguments();
+
+ // Set prototypes for the function maps.
global_context()->function_map()->set_prototype(*empty_function);
global_context()->function_instance_map()->set_prototype(*empty_function);
global_context()->function_without_prototype_map()->
set_prototype(*empty_function);
+
function_instance_map_writable_prototype_->set_prototype(*empty_function);
// Allocate the function map first and then patch the prototype later
+ Handle<Map> function_without_prototype_map(
+ global_context()->function_without_prototype_map());
Handle<Map> empty_fm = Factory::CopyMapDropDescriptors(
function_without_prototype_map);
empty_fm->set_instance_descriptors(
- *function_without_prototype_map_descriptors);
+ function_without_prototype_map->instance_descriptors());
empty_fm->set_prototype(global_context()->object_function()->prototype());
empty_function->set_map(*empty_fm);
return empty_function;
}
+
+
+Handle<DescriptorArray> Genesis::ComputeStrictFunctionInstanceDescriptor(
+ PrototypePropertyMode prototypeMode,
+ Handle<FixedArray> arguments,
+ Handle<FixedArray> caller) {
+ Handle<DescriptorArray> descriptors =
+ Factory::NewDescriptorArray(prototypeMode == DONT_ADD_PROTOTYPE ?
4 : 5);
+ PropertyAttributes attributes = static_cast<PropertyAttributes>(
+ DONT_ENUM | DONT_DELETE | READ_ONLY);
+
+ { // length
+ Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionLength);
+ CallbacksDescriptor d(*Factory::length_symbol(), *proxy, attributes);
+ descriptors->Set(0, &d);
+ }
+ { // name
+ Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionName);
+ CallbacksDescriptor d(*Factory::name_symbol(), *proxy, attributes);
+ descriptors->Set(1, &d);
+ }
+ { // arguments
+ CallbacksDescriptor d(*Factory::arguments_symbol(), *arguments,
attributes);
+ descriptors->Set(2, &d);
+ }
+ { // caller
+ CallbacksDescriptor d(*Factory::caller_symbol(), *caller, attributes);
+ descriptors->Set(3, &d);
+ }
+
+ // prototype
+ if (prototypeMode != DONT_ADD_PROTOTYPE) {
+ if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
+ attributes = static_cast<PropertyAttributes>(attributes &
~READ_ONLY);
+ }
+ Handle<Proxy> proxy = Factory::NewProxy(&Accessors::FunctionPrototype);
+ CallbacksDescriptor d(*Factory::prototype_symbol(), *proxy,
attributes);
+ descriptors->Set(4, &d);
+ }
+
+ descriptors->Sort();
+ return descriptors;
+}
+
+
+// ECMAScript 5th Edition, 13.2.3
+Handle<JSFunction> Genesis::CreateThrowTypeErrorFunction(
+ Builtins::Name builtin) {
+ Handle<String> name = Factory::LookupAsciiSymbol("ThrowTypeError");
+ Handle<JSFunction> throw_type_error =
+ Factory::NewFunctionWithoutPrototype(name, kStrictMode);
+ Handle<Code> code = Handle<Code>(Builtins::builtin(builtin));
+
+ throw_type_error->set_map(global_context()->strict_mode_function_map());
+ throw_type_error->set_code(*code);
+ throw_type_error->shared()->set_code(*code);
+ throw_type_error->shared()->DontAdaptArguments();
+
+ PreventExtensions(throw_type_error);
+
+ return throw_type_error;
+}
+
+
+Handle<Map> Genesis::CreateStrictModeFunctionMap(
+ PrototypePropertyMode prototype_mode,
+ Handle<JSFunction> empty_function,
+ Handle<FixedArray> arguments_callbacks,
+ Handle<FixedArray> caller_callbacks) {
+ Handle<Map> map = Factory::NewMap(JS_FUNCTION_TYPE, JSFunction::kSize);
+ Handle<DescriptorArray> descriptors =
+ ComputeStrictFunctionInstanceDescriptor(prototype_mode,
+ arguments_callbacks,
+ caller_callbacks);
+ map->set_instance_descriptors(*descriptors);
+ map->set_function_with_prototype(prototype_mode != DONT_ADD_PROTOTYPE);
+ map->set_prototype(*empty_function);
+ return map;
+}
+
+
+void Genesis::CreateStrictModeFunctionMaps(Handle<JSFunction> empty) {
+ // Create the callbacks arrays for ThrowTypeError functions.
+ // The get/set callacks are filled in after the maps are created below.
+ Handle<FixedArray> arguments = Factory::NewFixedArray(2, TENURED);
+ Handle<FixedArray> caller = Factory::NewFixedArray(2, TENURED);
+
+ // Allocate map for the strict mode function instances.
+ global_context()->set_strict_mode_function_instance_map(
+ *CreateStrictModeFunctionMap(
+ ADD_WRITEABLE_PROTOTYPE, empty, arguments, caller));
+
+ // Allocate map for the prototype-less strict mode instances.
+ global_context()->set_strict_mode_function_without_prototype_map(
+ *CreateStrictModeFunctionMap(
+ DONT_ADD_PROTOTYPE, empty, arguments, caller));
+
+ // Allocate map for the strict mode functions. This map is temporary,
used
+ // only for processing of builtins.
+ // Later the map is replaced with writable prototype map, allocated
below.
+ global_context()->set_strict_mode_function_map(
+ *CreateStrictModeFunctionMap(
+ ADD_READONLY_PROTOTYPE, empty, arguments, caller));
+
+ // The final map for the strict mode functions. Writeable prototype.
+ // This map is installed in MakeFunctionInstancePrototypeWritable.
+ strict_mode_function_instance_map_writable_prototype_ =
+ CreateStrictModeFunctionMap(
+ ADD_WRITEABLE_PROTOTYPE, empty, arguments, caller);
+
+ // Create the ThrowTypeError function instances.
+ Handle<JSFunction> arguments_throw =
+ CreateThrowTypeErrorFunction(Builtins::StrictFunctionArguments);
+ Handle<JSFunction> caller_throw =
+ CreateThrowTypeErrorFunction(Builtins::StrictFunctionCaller);
+
+ // Complete the callback fixed arrays.
+ arguments->set(0, *arguments_throw);
+ arguments->set(1, *arguments_throw);
+ caller->set(0, *caller_throw);
+ caller->set(1, *caller_throw);
+}
static void AddToWeakGlobalContextList(Context* context) {
@@ -1809,16 +1951,17 @@
void Genesis::MakeFunctionInstancePrototypeWritable() {
- // Make a new function map so all future functions
- // will have settable and enumerable prototype properties.
- HandleScope scope;
-
- Handle<DescriptorArray> function_map_descriptors =
- ComputeFunctionInstanceDescriptor(ADD_WRITEABLE_PROTOTYPE);
- Handle<Map> fm = Factory::CopyMapDropDescriptors(Top::function_map());
- fm->set_instance_descriptors(*function_map_descriptors);
- fm->set_function_with_prototype(true);
- Top::context()->global_context()->set_function_map(*fm);
+ // The maps with writable prototype are created in CreateEmptyFunction
+ // and CreateStrictModeFunctionMaps respectively. Initially the maps are
+ // created with read-only prototype for JS builtins processing.
+ ASSERT(!function_instance_map_writable_prototype_.is_null());
+ ASSERT(!strict_mode_function_instance_map_writable_prototype_.is_null());
+
+ // Replace function instance maps to make prototype writable.
+ global_context()->set_function_map(
+ *function_instance_map_writable_prototype_);
+ global_context()->set_strict_mode_function_map(
+ *strict_mode_function_instance_map_writable_prototype_);
}
@@ -1841,9 +1984,6 @@
AddToWeakGlobalContextList(*global_context_);
Top::set_context(*global_context_);
i::Counters::contexts_created_by_snapshot.Increment();
- JSFunction* empty_function =
- JSFunction::cast(global_context_->function_map()->prototype());
- empty_function_ = Handle<JSFunction>(empty_function);
Handle<GlobalObject> inner_global;
Handle<JSGlobalProxy> global_proxy =
CreateNewGlobals(global_template,
@@ -1858,6 +1998,7 @@
// We get here if there was no context snapshot.
CreateRoots();
Handle<JSFunction> empty_function = CreateEmptyFunction();
+ CreateStrictModeFunctionMaps(empty_function);
Handle<GlobalObject> inner_global;
Handle<JSGlobalProxy> global_proxy =
CreateNewGlobals(global_template, global_object, &inner_global);
=======================================
--- /branches/bleeding_edge/src/builtins.cc Tue Mar 15 04:01:21 2011
+++ /branches/bleeding_edge/src/builtins.cc Thu Mar 17 13:28:17 2011
@@ -956,6 +956,24 @@
return result_array;
}
+
+
+//
-----------------------------------------------------------------------------
+// Strict mode poison pills
+
+
+BUILTIN(StrictFunctionCaller) {
+ HandleScope scope;
+ return Top::Throw(*Factory::NewTypeError("strict_function_caller",
+ HandleVector<Object>(NULL,
0)));
+}
+
+
+BUILTIN(StrictFunctionArguments) {
+ HandleScope scope;
+ return Top::Throw(*Factory::NewTypeError("strict_function_arguments",
+ HandleVector<Object>(NULL,
0)));
+}
//
-----------------------------------------------------------------------------
=======================================
--- /branches/bleeding_edge/src/builtins.h Tue Mar 15 04:01:21 2011
+++ /branches/bleeding_edge/src/builtins.h Thu Mar 17 13:28:17 2011
@@ -58,7 +58,10 @@
V(FastHandleApiCall, NO_EXTRA_ARGUMENTS) \
V(HandleApiCallConstruct, NEEDS_CALLED_FUNCTION) \
V(HandleApiCallAsFunction, NO_EXTRA_ARGUMENTS) \
- V(HandleApiCallAsConstructor, NO_EXTRA_ARGUMENTS)
+ V(HandleApiCallAsConstructor, NO_EXTRA_ARGUMENTS) \
+ \
+ V(StrictFunctionCaller, NO_EXTRA_ARGUMENTS) \
+ V(StrictFunctionArguments, NO_EXTRA_ARGUMENTS)
// Define list of builtins implemented in assembly.
=======================================
--- /branches/bleeding_edge/src/contexts.h Tue Mar 15 04:01:21 2011
+++ /branches/bleeding_edge/src/contexts.h Thu Mar 17 13:28:17 2011
@@ -78,8 +78,13 @@
V(INSTANTIATE_FUN_INDEX, JSFunction, instantiate_fun) \
V(CONFIGURE_INSTANCE_FUN_INDEX, JSFunction, configure_instance_fun) \
V(FUNCTION_MAP_INDEX, Map, function_map) \
+ V(STRICT_MODE_FUNCTION_MAP_INDEX, Map, strict_mode_function_map) \
V(FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map,
function_without_prototype_map) \
+ V(STRICT_MODE_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX, Map, \
+ strict_mode_function_without_prototype_map) \
V(FUNCTION_INSTANCE_MAP_INDEX, Map, function_instance_map) \
+ V(STRICT_MODE_FUNCTION_INSTANCE_MAP_INDEX, Map, \
+ strict_mode_function_instance_map) \
V(JS_ARRAY_MAP_INDEX, Map, js_array_map)\
V(REGEXP_RESULT_MAP_INDEX, Map, regexp_result_map)\
V(ARGUMENTS_BOILERPLATE_INDEX, JSObject, arguments_boilerplate) \
@@ -185,8 +190,11 @@
JS_ARRAY_MAP_INDEX,
REGEXP_RESULT_MAP_INDEX,
FUNCTION_MAP_INDEX,
+ STRICT_MODE_FUNCTION_MAP_INDEX,
FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
+ STRICT_MODE_FUNCTION_WITHOUT_PROTOTYPE_MAP_INDEX,
FUNCTION_INSTANCE_MAP_INDEX,
+ STRICT_MODE_FUNCTION_INSTANCE_MAP_INDEX,
INITIAL_OBJECT_PROTOTYPE_INDEX,
BOOLEAN_FUNCTION_INDEX,
NUMBER_FUNCTION_INDEX,
=======================================
--- /branches/bleeding_edge/src/factory.cc Wed Mar 16 12:55:31 2011
+++ /branches/bleeding_edge/src/factory.cc Thu Mar 17 13:28:17 2011
@@ -351,7 +351,12 @@
Handle<Context> context,
PretenureFlag pretenure) {
Handle<JSFunction> result = BaseNewFunctionFromSharedFunctionInfo(
- function_info, Top::function_map(), pretenure);
+ function_info,
+ function_info->strict_mode()
+ ? Top::strict_mode_function_map()
+ : Top::function_map(),
+ pretenure);
+
result->set_context(*context);
int number_of_literals = function_info->num_literals();
Handle<FixedArray> literals =
@@ -584,7 +589,8 @@
Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String>
name,
Handle<Code> code)
{
- Handle<JSFunction> function = NewFunctionWithoutPrototype(name);
+ Handle<JSFunction> function = NewFunctionWithoutPrototype(name,
+
kNonStrictMode);
function->shared()->set_code(*code);
function->set_code(*code);
ASSERT(!function->has_initial_map());
@@ -809,18 +815,24 @@
Handle<JSFunction> Factory::NewFunctionWithoutPrototypeHelper(
- Handle<String> name) {
+ Handle<String> name,
+ StrictModeFlag strict_mode) {
Handle<SharedFunctionInfo> function_share = NewSharedFunctionInfo(name);
+ Handle<Map> map = strict_mode == kStrictMode
+ ? Top::strict_mode_function_without_prototype_map()
+ : Top::function_without_prototype_map();
CALL_HEAP_FUNCTION(Heap::AllocateFunction(
- *Top::function_without_prototype_map(),
+ *map,
*function_share,
*the_hole_value()),
JSFunction);
}
-Handle<JSFunction> Factory::NewFunctionWithoutPrototype(Handle<String>
name) {
- Handle<JSFunction> fun = NewFunctionWithoutPrototypeHelper(name);
+Handle<JSFunction> Factory::NewFunctionWithoutPrototype(
+ Handle<String> name,
+ StrictModeFlag strict_mode) {
+ Handle<JSFunction> fun = NewFunctionWithoutPrototypeHelper(name,
strict_mode);
fun->set_context(Top::context()->global_context());
return fun;
}
=======================================
--- /branches/bleeding_edge/src/factory.h Wed Mar 16 12:55:31 2011
+++ /branches/bleeding_edge/src/factory.h Thu Mar 17 13:28:17 2011
@@ -231,7 +231,9 @@
static Handle<JSFunction> NewFunction(Handle<String> name,
Handle<Object> prototype);
- static Handle<JSFunction> NewFunctionWithoutPrototype(Handle<String>
name);
+ static Handle<JSFunction> NewFunctionWithoutPrototype(
+ Handle<String> name,
+ StrictModeFlag strict_mode);
static Handle<JSFunction> NewFunction(Handle<Object> super, bool
is_global);
@@ -407,7 +409,8 @@
Handle<Object> prototype);
static Handle<JSFunction> NewFunctionWithoutPrototypeHelper(
- Handle<String> name);
+ Handle<String> name,
+ StrictModeFlag strict_mode);
static Handle<DescriptorArray> CopyAppendCallbackDescriptors(
Handle<DescriptorArray> array,
=======================================
--- /branches/bleeding_edge/src/handles.cc Tue Mar 15 04:01:21 2011
+++ /branches/bleeding_edge/src/handles.cc Thu Mar 17 13:28:17 2011
@@ -360,6 +360,11 @@
const bool skip_hidden_prototypes = false;
CALL_HEAP_FUNCTION(obj->SetPrototype(*value, skip_hidden_prototypes),
Object);
}
+
+
+Handle<Object> PreventExtensions(Handle<JSObject> object) {
+ CALL_HEAP_FUNCTION(object->PreventExtensions(), Object);
+}
Handle<Object> GetHiddenProperties(Handle<JSObject> obj,
=======================================
--- /branches/bleeding_edge/src/handles.h Tue Mar 15 04:01:21 2011
+++ /branches/bleeding_edge/src/handles.h Thu Mar 17 13:28:17 2011
@@ -370,6 +370,7 @@
Handle<Object> SetPrototype(Handle<JSFunction> function,
Handle<Object> prototype);
+Handle<Object> PreventExtensions(Handle<JSObject> object);
// Does lazy compilation of the given function. Returns true on success and
// false if the compilation resulted in a stack overflow.
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Tue Mar 15 04:01:21
2011
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Mar 17 13:28:17
2011
@@ -4916,9 +4916,10 @@
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
- if (scope()->is_function_scope() &&
+ if (!pretenure &&
+ scope()->is_function_scope() &&
function_info->num_literals() == 0 &&
- !pretenure) {
+ !function_info->strict_mode()) { // Strict mode functions use slow
path.
FastNewClosureStub stub;
frame()->EmitPush(Immediate(function_info));
return frame()->CallStub(&stub, 1);
=======================================
--- /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Thu Mar 17
07:30:48 2011
+++ /branches/bleeding_edge/src/ia32/full-codegen-ia32.cc Thu Mar 17
13:28:17 2011
@@ -1017,9 +1017,10 @@
// doesn't just get a copy of the existing unoptimized code.
if (!FLAG_always_opt &&
!FLAG_prepare_always_opt &&
+ !pretenure &&
scope()->is_function_scope() &&
info->num_literals() == 0 &&
- !pretenure) {
+ !info->strict_mode()) { // Strict mode functions go through slow
path.
FastNewClosureStub stub;
__ push(Immediate(info));
__ CallStub(&stub);
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Thu Mar 17
08:46:42 2011
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Thu Mar 17
13:28:17 2011
@@ -3739,7 +3739,8 @@
// space for nested functions that don't need literals cloning.
Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
- if (shared_info->num_literals() == 0 && !pretenure) {
+ if (!pretenure && shared_info->num_literals() == 0 &&
+ !shared_info->strict_mode()) {
FastNewClosureStub stub;
__ push(Immediate(shared_info));
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
=======================================
--- /branches/bleeding_edge/src/messages.js Tue Mar 15 04:01:21 2011
+++ /branches/bleeding_edge/src/messages.js Thu Mar 17 13:28:17 2011
@@ -230,6 +230,8 @@
strict_function: ["In strict mode code, functions can
only be declared at top level or immediately within another function." ],
strict_read_only_property: ["Cannot assign to read only
property '", "%0", "' of ", "%1"],
strict_cannot_assign: ["Cannot assign to read
only '", "%0", "' in strict mode"],
+ strict_function_caller: ["Cannot access property 'caller' of a
strict mode function"],
+ strict_function_arguments: ["Cannot access property 'arguments'
of a strict mode function"],
};
}
var message_type = %MessageGetType(message);
=======================================
--- /branches/bleeding_edge/src/objects.cc Tue Mar 15 04:01:21 2011
+++ /branches/bleeding_edge/src/objects.cc Thu Mar 17 13:28:17 2011
@@ -5536,12 +5536,21 @@
Object* JSFunction::RemovePrototype() {
- if (map() ==
context()->global_context()->function_without_prototype_map()) {
+ Context* global_context = context()->global_context();
+ Map* no_prototype_map = shared()->strict_mode()
+ ? global_context->strict_mode_function_without_prototype_map()
+ : global_context->function_without_prototype_map();
+
+ if (map() == no_prototype_map) {
// Be idempotent.
return this;
}
- ASSERT(map() == context()->global_context()->function_map());
- set_map(context()->global_context()->function_without_prototype_map());
+
+ ASSERT(!shared()->strict_mode() ||
+ map() == global_context->strict_mode_function_map());
+ ASSERT(shared()->strict_mode() || map() ==
global_context->function_map());
+
+ set_map(no_prototype_map);
set_prototype_or_initial_map(Heap::the_hole_value());
return this;
}
=======================================
--- /branches/bleeding_edge/src/runtime.cc Tue Mar 15 11:20:10 2011
+++ /branches/bleeding_edge/src/runtime.cc Thu Mar 17 13:28:17 2011
@@ -8045,11 +8045,14 @@
HandleScope scope;
ASSERT(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, func, 0);
- ASSERT(func->map()->instance_type() ==
- Top::function_instance_map()->instance_type());
- ASSERT(func->map()->instance_size() ==
- Top::function_instance_map()->instance_size());
- func->set_map(*Top::function_instance_map());
+
+ Handle<Map> map = func->shared()->strict_mode()
+ ? Top::strict_mode_function_instance_map()
+ : Top::function_instance_map();
+
+ ASSERT(func->map()->instance_type() == map->instance_type());
+ ASSERT(func->map()->instance_size() == map->instance_size());
+ func->set_map(*map);
return *func;
}
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc Tue Mar 15 04:01:21 2011
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc Thu Mar 17 13:28:17 2011
@@ -4260,9 +4260,10 @@
// Use the fast case closure allocation code that allocates in new
// space for nested functions that don't need literals cloning.
- if (scope()->is_function_scope() &&
+ if (!pretenure &&
+ scope()->is_function_scope() &&
function_info->num_literals() == 0 &&
- !pretenure) {
+ !function_info->strict_mode()) { // Strict mode functions use slow
path.
FastNewClosureStub stub;
frame_->Push(function_info);
Result answer = frame_->CallStub(&stub, 1);
=======================================
--- /branches/bleeding_edge/src/x64/full-codegen-x64.cc Thu Mar 17 07:30:48
2011
+++ /branches/bleeding_edge/src/x64/full-codegen-x64.cc Thu Mar 17 13:28:17
2011
@@ -1039,9 +1039,10 @@
// doesn't just get a copy of the existing unoptimized code.
if (!FLAG_always_opt &&
!FLAG_prepare_always_opt &&
+ !pretenure &&
scope()->is_function_scope() &&
info->num_literals() == 0 &&
- !pretenure) {
+ !info->strict_mode()) { // Strict mode functions use slow path.
FastNewClosureStub stub;
__ Push(info);
__ CallStub(&stub);
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Thu Mar 17
11:14:21 2011
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Thu Mar 17
13:28:17 2011
@@ -3539,7 +3539,8 @@
// space for nested functions that don't need literals cloning.
Handle<SharedFunctionInfo> shared_info = instr->shared_info();
bool pretenure = instr->hydrogen()->pretenure();
- if (shared_info->num_literals() == 0 && !pretenure) {
+ if (!pretenure && shared_info->num_literals() == 0 &&
+ !shared_info->strict_mode()) {
FastNewClosureStub stub;
__ Push(shared_info);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
=======================================
--- /branches/bleeding_edge/test/mjsunit/strict-mode.js Tue Mar 15 04:01:21
2011
+++ /branches/bleeding_edge/test/mjsunit/strict-mode.js Thu Mar 17 13:28:17
2011
@@ -976,3 +976,68 @@
assertEquals(["c", "d", "a", "b"], strict("a", "b"));
assertEquals(["c", "d", "c", "d"], nonstrict("a", "b"));
})();
+
+
+(function TestStrictFunctionPills() {
+ function strict() {
+ "use strict";
+ }
+ assertThrows(function() { strict.caller; }, TypeError);
+ assertThrows(function() { strict.arguments; }, TypeError);
+
+ var another = new Function("'use strict'");
+ assertThrows(function() { another.caller; }, TypeError);
+ assertThrows(function() { another.arguments; }, TypeError);
+
+ var third = (function() { "use strict"; return function() {}; })();
+ assertThrows(function() { third.caller; }, TypeError);
+ assertThrows(function() { third.arguments; }, TypeError);
+
+ function CheckPill(pill) {
+ assertEquals("function", typeof pill);
+ assertInstanceof(pill, Function);
+ assertThrows(function() { pill.property = "value"; }, TypeError);
+ assertThrows(pill, TypeError);
+ assertEquals(pill.prototype, (function(){}).prototype);
+ var d = Object.getOwnPropertyDescriptor(pill, "prototype");
+ assertFalse(d.writable);
+ assertFalse(d.configurable);
+ assertFalse(d.enumerable);
+ }
+
+ function CheckPillDescriptor(func, name) {
+ var descriptor = Object.getOwnPropertyDescriptor(func, name);
+ CheckPill(descriptor.get)
+ CheckPill(descriptor.set);
+ assertFalse(descriptor.enumerable);
+ assertFalse(descriptor.configurable);
+ }
+
+ CheckPillDescriptor(strict, "caller");
+ CheckPillDescriptor(strict, "arguments");
+ CheckPillDescriptor(another, "caller");
+ CheckPillDescriptor(another, "arguments");
+ CheckPillDescriptor(third, "caller");
+ CheckPillDescriptor(third, "arguments");
+})();
+
+
+(function TestStrictFunctionWritablePrototype() {
+ "use strict";
+ function TheClass() {
+ }
+ assertThrows(function() { TheClass.caller; }, TypeError);
+ assertThrows(function() { TheClass.arguments; }, TypeError);
+
+ // Strict functions must have writable prototype.
+ TheClass.prototype = {
+ func: function() { return "func_value"; },
+ get accessor() { return "accessor_value"; },
+ property: "property_value",
+ };
+
+ var o = new TheClass();
+ assertEquals(o.func(), "func_value");
+ assertEquals(o.accessor, "accessor_value");
+ assertEquals(o.property, "property_value");
+})();
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev