mirror-delay.js
date-delay.js
regexp-delay.js
+json-delay.js
'''.split()
}
-// Helper function used to check that a value is either not a function
-// or is loaded if it is a function.
-static void GenerateCheckNonFunctionOrLoaded(MacroAssembler* masm,
- Label* miss,
- Register value,
- Register scratch) {
+// Helper function used to check that a value is either not an object
+// or is loaded if it is an object.
+static void GenerateCheckNonObjectOrLoaded(MacroAssembler* masm,
+ Label* miss,
+ Register value,
+ Register scratch) {
Label done;
// Check if the value is a Smi.
__ tst(value, Operand(kSmiTagMask));
__ b(eq, &done);
- // Check if the value is a function.
- __ ldr(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
- __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
- __ cmp(scratch, Operand(JS_FUNCTION_TYPE));
- __ b(ne, &done);
- // Check if the function has been loaded.
- __ ldr(scratch,
- FieldMemOperand(value, JSFunction::kSharedFunctionInfoOffset));
- __ ldr(scratch,
- FieldMemOperand(scratch, SharedFunctionInfo::kLazyLoadDataOffset));
- __ cmp(scratch, Operand(Factory::undefined_value()));
+ // Check if the object has been loaded.
+ __ ldr(scratch, FieldMemOperand(value, JSObject::kMapOffset));
+ __ ldrb(scratch, FieldMemOperand(scratch, Map::kBitField2Offset));
+ __ tst(scratch, Operand(1 << Map::kNeedsLoading));
__ b(ne, miss);
__ bind(&done);
}
__ b(ne, miss);
// Check that the function has been loaded.
- __ ldr(r0, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
- __ ldr(r0, FieldMemOperand(r0, SharedFunctionInfo::kLazyLoadDataOffset));
- __ cmp(r0, Operand(Factory::undefined_value()));
+ __ ldr(r0, FieldMemOperand(r1, JSObject::kMapOffset));
+ __ ldrb(r0, FieldMemOperand(r0, Map::kBitField2Offset));
+ __ tst(r0, Operand(1 << Map::kNeedsLoading));
__ b(ne, miss);
// Patch the receiver with the global proxy if necessary.
__ bind(&probe);
GenerateDictionaryLoad(masm, &miss, r1, r0);
- GenerateCheckNonFunctionOrLoaded(masm, &miss, r0, r1);
+ GenerateCheckNonObjectOrLoaded(masm, &miss, r0, r1);
__ Ret();
// Global object access: Check access rights.
global_context()->set_regexp_function(*regexp_fun);
}
+ { // -- J S O N
+ Handle<String> name = Factory::NewStringFromAscii(CStrVector("JSON"));
+ Handle<JSFunction> cons = Factory::NewFunction(
+ name,
+ Factory::the_hole_value());
+ cons->SetInstancePrototype(global_context()->initial_object_prototype());
+ cons->SetInstanceClassName(*name);
+ Handle<JSObject> json_object = Factory::NewJSObject(cons, TENURED);
+ ASSERT(json_object->IsJSObject());
+ SetProperty(global, name, json_object, DONT_ENUM);
+ global_context()->set_json_object(*json_object);
+ }
+
{ // --- arguments_boilerplate_
// Make sure we can recognize argument objects at runtime.
// This is done by introducing an anonymous function with
Natives::GetIndex("regexp"),
Top::global_context(),
Handle<Context>(Top::context()->runtime_context()));
+ SetupLazy(Handle<JSObject>(global_context()->json_object()),
+ Natives::GetIndex("json"),
+ Top::global_context(),
+ Handle<Context>(Top::context()->runtime_context()));
} else if (strlen(FLAG_natives_file) != 0) {
// Otherwise install natives from natives file if file exists and
V(OBJECT_FUNCTION_INDEX, JSFunction, object_function) \
V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
V(DATE_FUNCTION_INDEX, JSFunction, date_function) \
+ V(JSON_OBJECT_INDEX, JSObject, json_object) \
V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \
V(INITIAL_OBJECT_PROTOTYPE_INDEX, JSObject, initial_object_prototype) \
V(CREATE_DATE_FUN_INDEX, JSFunction, create_date_fun) \
OBJECT_FUNCTION_INDEX,
ARRAY_FUNCTION_INDEX,
DATE_FUNCTION_INDEX,
+ JSON_OBJECT_INDEX,
REGEXP_FUNCTION_INDEX,
CREATE_DATE_FUN_INDEX,
TO_NUMBER_FUN_INDEX,
}
+function PadInt(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+}
+
+
+function DateToISOString() {
+ return this.getUTCFullYear() + '-' + PadInt(this.getUTCMonth() + 1) +
+ '-' + PadInt(this.getUTCDate()) + 'T' + PadInt(this.getUTCHours()) +
+ ':' + PadInt(this.getUTCMinutes()) + ':' + PadInt(this.getUTCSeconds()) +
+ 'Z';
+}
+
+
+function DateToJSON(key) {
+ return CheckJSONPrimitive(this.toISOString());
+}
+
+
// -------------------------------------------------------------------
function SetupDate() {
"toGMTString", DateToGMTString,
"toUTCString", DateToUTCString,
"getYear", DateGetYear,
- "setYear", DateSetYear
+ "setYear", DateSetYear,
+ "toISOString", DateToISOString,
+ "toJSON", DateToJSON
));
}
}
-void LoadLazy(Handle<JSFunction> fun, bool* pending_exception) {
+void LoadLazy(Handle<JSObject> obj, bool* pending_exception) {
HandleScope scope;
- Handle<FixedArray> info(FixedArray::cast(fun->shared()->lazy_load_data()));
+ Handle<FixedArray> info(FixedArray::cast(obj->map()->constructor()));
int index = Smi::cast(info->get(0))->value();
ASSERT(index >= 0);
Handle<Context> compile_context(Context::cast(info->get(1)));
// Reset the lazy load data before running the script to make sure
// not to get recursive lazy loading.
- fun->shared()->set_lazy_load_data(Heap::undefined_value());
+ obj->map()->set_needs_loading(false);
+ obj->map()->set_constructor(info->get(3));
// Run the script.
Handle<JSFunction> script_fun(
Factory::NewFunctionFromBoilerplate(boilerplate, function_context));
Execution::Call(script_fun, receiver, 0, NULL, pending_exception);
- // If lazy loading failed, restore the unloaded state of fun.
- if (*pending_exception) fun->shared()->set_lazy_load_data(*info);
+ // If lazy loading failed, restore the unloaded state of obj.
+ if (*pending_exception) {
+ obj->map()->set_needs_loading(true);
+ obj->map()->set_constructor(*info);
+ }
}
-void SetupLazy(Handle<JSFunction> fun,
+void SetupLazy(Handle<JSObject> obj,
int index,
Handle<Context> compile_context,
Handle<Context> function_context) {
- Handle<FixedArray> arr = Factory::NewFixedArray(3);
+ Handle<FixedArray> arr = Factory::NewFixedArray(4);
arr->set(0, Smi::FromInt(index));
arr->set(1, *compile_context); // Compile in this context
arr->set(2, *function_context); // Set function context to this
- fun->shared()->set_lazy_load_data(*arr);
+ arr->set(3, obj->map()->constructor()); // Remember the constructor
+ Handle<Map> old_map(obj->map());
+ Handle<Map> new_map = Factory::CopyMap(old_map);
+ obj->set_map(*new_map);
+ new_map->set_needs_loading(true);
+ // Store the lazy loading info in the constructor field. We'll
+ // reestablish the constructor from the fixed array after loading.
+ new_map->set_constructor(*arr);
+ ASSERT(!obj->IsLoaded());
}
} } // namespace v8::internal
bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag);
// These deal with lazily loaded properties.
-void SetupLazy(Handle<JSFunction> fun,
+void SetupLazy(Handle<JSObject> obj,
int index,
Handle<Context> compile_context,
Handle<Context> function_context);
-void LoadLazy(Handle<JSFunction> fun, bool* pending_exception);
+void LoadLazy(Handle<JSObject> obj, bool* pending_exception);
class NoHandleAllocation BASE_EMBEDDED {
public:
map->set_code_cache(empty_fixed_array());
map->set_unused_property_fields(0);
map->set_bit_field(0);
+ map->set_bit_field2(0);
return map;
}
share->set_formal_parameter_count(0);
share->set_instance_class_name(Object_symbol());
share->set_function_data(undefined_value());
- share->set_lazy_load_data(undefined_value());
share->set_script(undefined_value());
share->set_start_position_and_type(0);
share->set_debug_info(undefined_value());
}
-// Helper function used to check that a value is either not a function
-// or is loaded if it is a function.
-static void GenerateCheckNonFunctionOrLoaded(MacroAssembler* masm, Label* miss,
- Register value, Register scratch) {
+// Helper function used to check that a value is either not an object
+// or is loaded if it is an object.
+static void GenerateCheckNonObjectOrLoaded(MacroAssembler* masm, Label* miss,
+ Register value, Register scratch) {
Label done;
// Check if the value is a Smi.
__ test(value, Immediate(kSmiTagMask));
__ j(zero, &done, not_taken);
- // Check if the value is a function.
- __ CmpObjectType(value, JS_FUNCTION_TYPE, scratch);
- __ j(not_equal, &done, taken);
- // Check if the function has been loaded.
- __ mov(scratch, FieldOperand(value, JSFunction::kSharedFunctionInfoOffset));
- __ mov(scratch,
- FieldOperand(scratch, SharedFunctionInfo::kLazyLoadDataOffset));
- __ cmp(scratch, Factory::undefined_value());
- __ j(not_equal, miss, not_taken);
+ // Check if the object has been loaded.
+ __ mov(scratch, FieldOperand(value, JSFunction::kMapOffset));
+ __ mov(scratch, FieldOperand(scratch, Map::kBitField2Offset));
+ __ test(scratch, Immediate(1 << Map::kNeedsLoading));
+ __ j(not_zero, miss, not_taken);
__ bind(&done);
}
__ j(not_zero, &slow, not_taken);
// Probe the dictionary leaving result in ecx.
GenerateDictionaryLoad(masm, &slow, ebx, ecx, edx, eax);
- GenerateCheckNonFunctionOrLoaded(masm, &slow, ecx, edx);
+ GenerateCheckNonObjectOrLoaded(masm, &slow, ecx, edx);
__ mov(eax, Operand(ecx));
__ IncrementCounter(&Counters::keyed_load_generic_symbol, 1);
__ ret(0);
__ j(not_equal, miss, not_taken);
// Check that the function has been loaded.
- __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
- __ mov(edx, FieldOperand(edx, SharedFunctionInfo::kLazyLoadDataOffset));
- __ cmp(edx, Factory::undefined_value());
- __ j(not_equal, miss, not_taken);
+ __ mov(edx, FieldOperand(edi, JSFunction::kMapOffset));
+ __ mov(edx, FieldOperand(edx, Map::kBitField2Offset));
+ __ test(edx, Immediate(1 << Map::kNeedsLoading));
+ __ j(not_zero, miss, not_taken);
// Patch the receiver with the global proxy if necessary.
if (is_global_object) {
// Search the dictionary placing the result in eax.
__ bind(&probe);
GenerateDictionaryLoad(masm, &miss, edx, eax, ebx, ecx);
- GenerateCheckNonFunctionOrLoaded(masm, &miss, eax, edx);
+ GenerateCheckNonObjectOrLoaded(masm, &miss, eax, edx);
__ ret(0);
// Global object access: Check access rights.
--- /dev/null
+// Copyright 2009 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.
+
+var $JSON = global.JSON;
+
+function IsValidJSON(s) {
+ // All empty whitespace is not valid.
+ if (/^\s*$/.test(s))
+ return false;
+
+ // This is taken from http://www.json.org/json2.js which is released to the
+ // public domain.
+
+ var backslashesRe = /\\["\\\/bfnrtu]/g;
+ var simpleValuesRe =
+ /"[^"\\\n\r\x00-\x1f\x7f-\x9f]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
+ var openBracketsRe = /(?:^|:|,)(?:[\s]*\[)+/g;
+ var remainderRe = /^[\],:{}\s]*$/;
+
+ return remainderRe.test(s.replace(backslashesRe, '@').
+ replace(simpleValuesRe, ']').
+ replace(openBracketsRe, ''));
+}
+
+function ParseJSONUnfiltered(text) {
+ var s = $String(text);
+ if (IsValidJSON(s)) {
+ try {
+ return global.eval('(' + s + ')');
+ } catch (e) {
+ // ignore exceptions
+ }
+ }
+ throw MakeSyntaxError('invalid_json', [s]);
+}
+
+function Revive(holder, name, reviver) {
+ var val = holder[name];
+ if (IS_OBJECT(val)) {
+ if (IS_ARRAY(val)) {
+ var length = val.length;
+ for (var i = 0; i < length; i++) {
+ var newElement = Revive(val, $String(i), reviver);
+ val[i] = newElement;
+ }
+ } else {
+ for (var p in val) {
+ if (ObjectHasOwnProperty.call(val, p)) {
+ var newElement = Revive(val, p, reviver);
+ if (IS_UNDEFINED(newElement)) {
+ delete val[p];
+ } else {
+ val[p] = newElement;
+ }
+ }
+ }
+ }
+ }
+ return reviver.call(holder, name, val);
+}
+
+function JSONParse(text, reviver) {
+ var unfiltered = ParseJSONUnfiltered(text);
+ if (IS_FUNCTION(reviver)) {
+ return Revive({'': unfiltered}, '', reviver);
+ } else {
+ return unfiltered;
+ }
+}
+
+var characterQuoteCache = {
+ '\"': '\\"',
+ '\\': '\\\\',
+ '/': '\\/',
+ '\b': '\\b',
+ '\f': '\\f',
+ '\n': '\\n',
+ '\r': '\\r',
+ '\t': '\\t',
+ '\x0B': '\\u000b'
+};
+
+function QuoteSingleJSONCharacter(c) {
+ if (c in characterQuoteCache)
+ return characterQuoteCache[c];
+ var charCode = c.charCodeAt(0);
+ var result;
+ if (charCode < 16) result = '\\u000';
+ else if (charCode < 256) result = '\\u00';
+ else if (charCode < 4096) result = '\\u0';
+ else result = '\\u';
+ result += charCode.toString(16);
+ characterQuoteCache[c] = result;
+ return result;
+}
+
+function QuoteJSONString(str) {
+ var quotable = /[\\\"\x00-\x1f\x80-\uffff]/g;
+ return '"' + str.replace(quotable, QuoteSingleJSONCharacter) + '"';
+}
+
+function StackContains(stack, val) {
+ var length = stack.length;
+ for (var i = 0; i < length; i++) {
+ if (stack[i] === val)
+ return true;
+ }
+ return false;
+}
+
+function SerializeArray(value, replacer, stack, indent, gap) {
+ if (StackContains(stack, value))
+ throw MakeTypeError('circular_structure', []);
+ stack.push(value);
+ var stepback = indent;
+ indent += gap;
+ var partial = [];
+ var len = value.length;
+ for (var i = 0; i < len; i++) {
+ var strP = JSONSerialize($String(i), value, replacer, stack,
+ indent, gap);
+ if (IS_UNDEFINED(strP))
+ strP = "null";
+ partial.push(strP);
+ }
+ var final;
+ if (gap == "") {
+ final = "[" + partial.join(",") + "]";
+ } else if (partial.length > 0) {
+ var separator = ",\n" + indent;
+ final = "[\n" + indent + partial.join(separator) + "\n" +
+ stepback + "]";
+ } else {
+ final = "[]";
+ }
+ stack.pop();
+ return final;
+}
+
+function SerializeObject(value, replacer, stack, indent, gap) {
+ if (StackContains(stack, value))
+ throw MakeTypeError('circular_structure', []);
+ stack.push(value);
+ var stepback = indent;
+ indent += gap;
+ var partial = [];
+ if (IS_ARRAY(replacer)) {
+ var length = replacer.length;
+ for (var i = 0; i < length; i++) {
+ if (ObjectHasOwnProperty.call(replacer, i)) {
+ var p = replacer[i];
+ var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
+ if (!IS_UNDEFINED(strP)) {
+ var member = QuoteJSONString(p) + ":";
+ if (gap != "") member += " ";
+ member += strP;
+ partial.push(member);
+ }
+ }
+ }
+ } else {
+ for (var p in value) {
+ if (ObjectHasOwnProperty.call(value, p)) {
+ var strP = JSONSerialize(p, value, replacer, stack, indent, gap);
+ if (!IS_UNDEFINED(strP)) {
+ var member = QuoteJSONString(p) + ":";
+ if (gap != "") member += " ";
+ member += strP;
+ partial.push(member);
+ }
+ }
+ }
+ }
+ var final;
+ if (gap == "") {
+ final = "{" + partial.join(",") + "}";
+ } else if (partial.length > 0) {
+ var separator = ",\n" + indent;
+ final = "{\n" + indent + partial.join(separator) + "\n" +
+ stepback + "}";
+ } else {
+ final = "{}";
+ }
+ stack.pop();
+ return final;
+}
+
+function JSONSerialize(key, holder, replacer, stack, indent, gap) {
+ var value = holder[key];
+ if (IS_OBJECT(value) && value) {
+ var toJSON = value.toJSON;
+ if (IS_FUNCTION(toJSON))
+ value = toJSON.call(value, key);
+ }
+ if (IS_FUNCTION(replacer))
+ value = replacer.call(holder, key, value);
+ // Unwrap value if necessary
+ if (IS_OBJECT(value)) {
+ if (IS_NUMBER_WRAPPER(value)) {
+ value = $Number(value);
+ } else if (IS_STRING_WRAPPER(value)) {
+ value = $String(value);
+ }
+ }
+ switch (typeof value) {
+ case "string":
+ return QuoteJSONString(value);
+ case "object":
+ if (!value) {
+ return "null";
+ } else if (IS_ARRAY(value)) {
+ return SerializeArray(value, replacer, stack, indent, gap);
+ } else {
+ return SerializeObject(value, replacer, stack, indent, gap);
+ }
+ case "number":
+ return $isFinite(value) ? $String(value) : "null";
+ case "boolean":
+ return value ? "true" : "false";
+ }
+}
+
+function JSONStringify(value, replacer, space) {
+ var stack = [];
+ var indent = "";
+ if (IS_OBJECT(space)) {
+ // Unwrap 'space' if it is wrapped
+ if (IS_NUMBER_WRAPPER(space)) {
+ space = $Number(space);
+ } else if (IS_STRING_WRAPPER(space)) {
+ space = $String(space);
+ }
+ }
+ var gap;
+ if (IS_NUMBER(space)) {
+ space = $Math.min(space, 100);
+ gap = "";
+ for (var i = 0; i < space; i++)
+ gap += " ";
+ } else if (IS_STRING(space)) {
+ gap = space;
+ } else {
+ gap = "";
+ }
+ return JSONSerialize('', {'': value}, replacer, stack, indent, gap);
+}
+
+function SetupJSON() {
+ InstallFunctions($JSON, DONT_ENUM, $Array(
+ "parse", JSONParse,
+ "stringify", JSONStringify
+ ));
+}
+
+SetupJSON();
macro IS_REGEXP(arg) = %HasRegExpClass(arg);
macro IS_ARRAY(arg) = %HasArrayClass(arg);
macro IS_DATE(arg) = %HasDateClass(arg);
+macro IS_NUMBER_WRAPPER(arg) = %HasNumberClass(arg);
+macro IS_STRING_WRAPPER(arg) = %HasStringClass(arg);
macro IS_ERROR(arg) = (%ClassOf(arg) === 'Error');
macro IS_SCRIPT(arg) = (%ClassOf(arg) === 'Script');
macro FLOOR(arg) = %Math_floor(arg);
illegal_return: "Illegal return statement",
error_loading_debugger: "Error loading debugger %0",
no_input_to_regexp: "No input to %0",
+ result_not_primitive: "Result of %0 must be a primitive, was %1",
+ invalid_json: "String '%0' is not valid JSON",
+ circular_structure: "Converting circular structure to JSON"
};
code()->ShortPrint();
PrintF("\n - source code = ");
GetSourceCode()->ShortPrint();
- PrintF("\n - lazy load: %s",
- lazy_load_data() == Heap::undefined_value() ? "no" : "yes");
// Script files are often large, hard to read.
// PrintF("\n - script =");
// script()->Print();
VerifyObjectField(kCodeOffset);
VerifyObjectField(kInstanceClassNameOffset);
VerifyObjectField(kExternalReferenceDataOffset);
- VerifyObjectField(kLazyLoadDataOffset);
VerifyObjectField(kScriptOffset);
VerifyObjectField(kDebugInfoOffset);
}
}
+byte Map::bit_field2() {
+ return READ_BYTE_FIELD(this, kBitField2Offset);
+}
+
+
+void Map::set_bit_field2(byte value) {
+ WRITE_BYTE_FIELD(this, kBitField2Offset, value);
+}
+
+
void Map::set_non_instance_prototype(bool value) {
if (value) {
set_bit_field(bit_field() | (1 << kHasNonInstancePrototype));
kInstanceClassNameOffset)
ACCESSORS(SharedFunctionInfo, function_data, Object,
kExternalReferenceDataOffset)
-ACCESSORS(SharedFunctionInfo, lazy_load_data, Object, kLazyLoadDataOffset)
ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset)
ACCESSORS(SharedFunctionInfo, debug_info, Object, kDebugInfoOffset)
ACCESSORS(SharedFunctionInfo, inferred_name, String, kInferredNameOffset)
}
-bool JSFunction::IsLoaded() {
- return shared()->lazy_load_data() == Heap::undefined_value();
+bool JSObject::IsLoaded() {
+ return !map()->needs_loading();
}
Handle<Object> receiver_handle(receiver);
Handle<String> name_handle(name);
bool pending_exception;
- LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())),
+ LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())),
&pending_exception);
if (pending_exception) return Failure::Exception();
return this_handle->GetPropertyWithReceiver(*receiver_handle,
Handle<String> name_handle(name);
Handle<Object> value_handle(value);
bool pending_exception;
- LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())),
+ LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())),
&pending_exception);
if (pending_exception) return Failure::Exception();
return this_handle->SetProperty(*name_handle, *value_handle, attributes);
Handle<JSObject> this_handle(this);
Handle<String> name_handle(name);
bool pending_exception;
- LoadLazy(Handle<JSFunction>(JSFunction::cast(result->GetValue())),
+ LoadLazy(Handle<JSObject>(JSObject::cast(result->GetLazyValue())),
&pending_exception);
if (pending_exception) return Failure::Exception();
return this_handle->DeleteProperty(*name_handle);
Map::cast(result)->set_inobject_properties(inobject_properties());
Map::cast(result)->set_unused_property_fields(unused_property_fields());
Map::cast(result)->set_bit_field(bit_field());
+ Map::cast(result)->set_bit_field2(bit_field2());
Map::cast(result)->ClearCodeCache();
return result;
}
String* name,
PropertyAttributes* attributes);
+ // Tells whether this object needs to be loaded.
+ inline bool IsLoaded();
+
bool HasProperty(String* name) {
return GetPropertyAttribute(name) != ABSENT;
}
inline byte bit_field();
inline void set_bit_field(byte value);
+ // Bit field 2.
+ inline byte bit_field2();
+ inline void set_bit_field2(byte value);
+
// Tells whether the object in the prototype property will be used
// for instances created from this function. If the prototype
// property is set to a value that is not a JSObject, the prototype
return ((1 << kIsUndetectable) & bit_field()) != 0;
}
+ inline void set_needs_loading(bool value) {
+ if (value) {
+ set_bit_field2(bit_field2() | (1 << kNeedsLoading));
+ } else {
+ set_bit_field2(bit_field2() & ~(1 << kNeedsLoading));
+ }
+ }
+
+ // Does this object or function require a lazily loaded script to be
+ // run before being used?
+ inline bool needs_loading() {
+ return ((1 << kNeedsLoading) & bit_field2()) != 0;
+ }
+
// Tells whether the instance has a call-as-function handler.
inline void set_has_instance_call_handler() {
set_bit_field(bit_field() | (1 << kHasInstanceCallHandler));
static const int kInstanceTypeOffset = kInstanceAttributesOffset + 0;
static const int kUnusedPropertyFieldsOffset = kInstanceAttributesOffset + 1;
static const int kBitFieldOffset = kInstanceAttributesOffset + 2;
- // The byte at position 3 is not in use at the moment.
+ static const int kBitField2Offset = kInstanceAttributesOffset + 3;
// Bit positions for bit field.
static const int kUnused = 0; // To be used for marking recently used maps.
static const int kIsUndetectable = 5;
static const int kHasInstanceCallHandler = 6;
static const int kIsAccessCheckNeeded = 7;
+
+ // Bit positions for but field 2
+ static const int kNeedsLoading = 0;
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Map);
};
// on objects.
DECL_ACCESSORS(function_data, Object)
- // [lazy load data]: If the function has lazy loading, this field
- // contains contexts and other data needed to load it.
- DECL_ACCESSORS(lazy_load_data, Object)
-
// [script info]: Script from which the function originates.
DECL_ACCESSORS(script, Object)
kExpectedNofPropertiesOffset + kIntSize;
static const int kExternalReferenceDataOffset =
kInstanceClassNameOffset + kPointerSize;
- static const int kLazyLoadDataOffset =
- kExternalReferenceDataOffset + kPointerSize;
- static const int kScriptOffset = kLazyLoadDataOffset + kPointerSize;
+ static const int kScriptOffset = kExternalReferenceDataOffset + kPointerSize;
static const int kStartPositionAndTypeOffset = kScriptOffset + kPointerSize;
static const int kEndPositionOffset = kStartPositionAndTypeOffset + kIntSize;
static const int kFunctionTokenPositionOffset = kEndPositionOffset + kIntSize;
// function.
inline bool IsBoilerplate();
- // Tells whether this function needs to be loaded.
- inline bool IsLoaded();
-
// [literals]: Fixed array holding the materialized literals.
//
// If the function contains object, regexp or array literals, the
// Tells whether the value needs to be loaded.
bool IsLoaded() {
if (lookup_type_ == DESCRIPTOR_TYPE || lookup_type_ == DICTIONARY_TYPE) {
- Object* value = GetValue();
- if (value->IsJSFunction()) {
- return JSFunction::cast(value)->IsLoaded();
- }
+ Object* target = GetLazyValue();
+ return !target->IsJSObject() || JSObject::cast(target)->IsLoaded();
}
return true;
}
+ Object* GetLazyValue() {
+ switch (type()) {
+ case FIELD:
+ return holder()->FastPropertyAt(GetFieldIndex());
+ case NORMAL:
+ return holder()->property_dictionary()->ValueAt(GetDictionaryEntry());
+ case CONSTANT_FUNCTION:
+ return GetConstantFunction();
+ default:
+ return Smi::FromInt(0);
+ }
+ }
+
Map* GetTransitionMap() {
ASSERT(lookup_type_ == DESCRIPTOR_TYPE);
ASSERT(type() == MAP_TRANSITION);
}
+function StringToJSON(key) {
+ return CheckJSONPrimitive(this.valueOf());
+}
+
+
// -------------------------------------------------------------------
function SetupString() {
"small", StringSmall,
"strike", StringStrike,
"sub", StringSub,
- "sup", StringSup
+ "sup", StringSup,
+ "toJSON", StringToJSON
));
}
}
+function BooleanToJSON(key) {
+ return CheckJSONPrimitive(this.valueOf());
+}
+
+
// ----------------------------------------------------------------------------
function SetupBoolean() {
InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
"toString", BooleanToString,
- "valueOf", BooleanValueOf
+ "valueOf", BooleanValueOf,
+ "toJSON", BooleanToJSON
));
}
}
+function CheckJSONPrimitive(val) {
+ if (!IsPrimitive(val))
+ throw MakeTypeError('result_not_primitive', ['toJSON', val]);
+ return val;
+}
+
+
+function NumberToJSON(key) {
+ return CheckJSONPrimitive(this.valueOf());
+}
+
+
// ----------------------------------------------------------------------------
function SetupNumber() {
"valueOf", NumberValueOf,
"toFixed", NumberToFixed,
"toExponential", NumberToExponential,
- "toPrecision", NumberToPrecision
+ "toPrecision", NumberToPrecision,
+ "toJSON", NumberToJSON
));
}
--- /dev/null
+// Copyright 2009 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.
+
+function GenericToJSONChecks(Constructor, value, alternative) {
+ var n1 = new Constructor(value);
+ n1.valueOf = function () { return alternative; };
+ assertEquals(alternative, n1.toJSON());
+ var n2 = new Constructor(value);
+ n2.valueOf = null;
+ assertThrows(function () { n2.toJSON(); }, TypeError);
+ var n3 = new Constructor(value);
+ n3.valueOf = function () { return {}; };
+ assertThrows(function () { n3.toJSON(); }, TypeError, 'result_not_primitive');
+ var n4 = new Constructor(value);
+ n4.valueOf = function () {
+ assertEquals(0, arguments.length);
+ assertEquals(this, n4);
+ return null;
+ };
+ assertEquals(null, n4.toJSON());
+}
+
+// Number toJSON
+assertEquals(3, (3).toJSON());
+assertEquals(3, (3).toJSON(true));
+assertEquals(4, (new Number(4)).toJSON());
+GenericToJSONChecks(Number, 5, 6);
+
+// Boolean toJSON
+assertEquals(true, (true).toJSON());
+assertEquals(true, (true).toJSON(false));
+assertEquals(false, (false).toJSON());
+assertEquals(true, (new Boolean(true)).toJSON());
+GenericToJSONChecks(Boolean, true, false);
+GenericToJSONChecks(Boolean, false, true);
+
+// String toJSON
+assertEquals("flot", "flot".toJSON());
+assertEquals("flot", "flot".toJSON(3));
+assertEquals("tolf", (new String("tolf")).toJSON());
+GenericToJSONChecks(String, "x", "y");
+
+// Date toJSON
+assertEquals("1970-01-01T00:00:00Z", new Date(0).toJSON());
+assertEquals("1979-01-11T08:00:00Z", new Date("1979-01-11 08:00 GMT").toJSON());
+assertEquals("2005-05-05T05:05:05Z", new Date("2005-05-05 05:05:05 GMT").toJSON());
+var n1 = new Date(10000);
+n1.toISOString = function () { return "foo"; };
+assertEquals("foo", n1.toJSON());
+var n2 = new Date(10001);
+n2.toISOString = null;
+assertThrows(function () { n2.toJSON(); }, TypeError);
+var n3 = new Date(10002);
+n3.toISOString = function () { return {}; };
+assertThrows(function () { n3.toJSON(); }, TypeError, "result_not_primitive");
+var n4 = new Date(10003);
+n4.toISOString = function () {
+ assertEquals(0, arguments.length);
+ assertEquals(this, n4);
+ return null;
+};
+assertEquals(null, n4.toJSON());
+
+assertEquals(Object.prototype, JSON.__proto__);
+assertEquals("[object JSON]", Object.prototype.toString.call(JSON));
+
+// DontEnum
+for (var p in this)
+ assertFalse(p == "JSON");
+
+// Parse
+
+assertEquals({}, JSON.parse("{}"));
+assertEquals(null, JSON.parse("null"));
+assertEquals(true, JSON.parse("true"));
+assertEquals(false, JSON.parse("false"));
+assertEquals("foo", JSON.parse('"foo"'));
+assertEquals("f\no", JSON.parse('"f\\no"'));
+assertEquals(1.1, JSON.parse("1.1"));
+assertEquals(1, JSON.parse("1.0"));
+assertEquals(0.0000000003, JSON.parse("3e-10"));
+assertEquals([], JSON.parse("[]"));
+assertEquals([1], JSON.parse("[1]"));
+assertEquals([1, "2", true, null], JSON.parse('[1, "2", true, null]'));
+
+function GetFilter(name) {
+ function Filter(key, value) {
+ return (key == name) ? undefined : value;
+ }
+ return Filter;
+}
+
+var pointJson = '{"x": 1, "y": 2}';
+assertEquals({'x': 1, 'y': 2}, JSON.parse(pointJson));
+assertEquals({'x': 1}, JSON.parse(pointJson, GetFilter('y')));
+assertEquals({'y': 2}, JSON.parse(pointJson, GetFilter('x')));
+assertEquals([1, 2, 3], JSON.parse("[1, 2, 3]"));
+assertEquals([1, undefined, 3], JSON.parse("[1, 2, 3]", GetFilter(1)));
+assertEquals([1, 2, undefined], JSON.parse("[1, 2, 3]", GetFilter(2)));
+
+function DoubleNumbers(key, value) {
+ return (typeof value == 'number') ? 2 * value : value;
+}
+
+var deepObject = '{"a": {"b": 1, "c": 2}, "d": {"e": {"f": 3}}}';
+assertEquals({"a": {"b": 1, "c": 2}, "d": {"e": {"f": 3}}},
+ JSON.parse(deepObject));
+assertEquals({"a": {"b": 2, "c": 4}, "d": {"e": {"f": 6}}},
+ JSON.parse(deepObject, DoubleNumbers));
+
+function TestInvalid(str) {
+ assertThrows(function () { JSON.parse(str); }, SyntaxError);
+}
+
+TestInvalid('"abc\x00def"');
+TestInvalid('"abc\x10def"');
+TestInvalid('"abc\x1fdef"');
+
+TestInvalid("[1, 2");
+TestInvalid('{"x": 3');
+
+// Stringify
+
+assertEquals("true", JSON.stringify(true));
+assertEquals("false", JSON.stringify(false));
+assertEquals("null", JSON.stringify(null));
+assertEquals("false", JSON.stringify({toJSON: function () { return false; }}));
+assertEquals("4", JSON.stringify(4));
+assertEquals('"foo"', JSON.stringify("foo"));
+assertEquals("null", JSON.stringify(Infinity));
+assertEquals("null", JSON.stringify(-Infinity));
+assertEquals("null", JSON.stringify(NaN));
+assertEquals("4", JSON.stringify(new Number(4)));
+assertEquals('"bar"', JSON.stringify(new String("bar")));
+
+assertEquals('"foo\\u0000bar"', JSON.stringify("foo\0bar"));
+assertEquals('"f\\"o\'o\\\\b\\ba\\fr\\nb\\ra\\tz"',
+ JSON.stringify("f\"o\'o\\b\ba\fr\nb\ra\tz"));
+
+assertEquals("[1,2,3]", JSON.stringify([1, 2, 3]));
+assertEquals("[\n 1,\n 2,\n 3\n]", JSON.stringify([1, 2, 3], null, 1));
+assertEquals("[\n 1,\n 2,\n 3\n]", JSON.stringify([1, 2, 3], null, 2));
+assertEquals("[\n 1,\n 2,\n 3\n]",
+ JSON.stringify([1, 2, 3], null, new Number(2)));
+assertEquals("[\n^1,\n^2,\n^3\n]", JSON.stringify([1, 2, 3], null, "^"));
+assertEquals("[\n^1,\n^2,\n^3\n]",
+ JSON.stringify([1, 2, 3], null, new String("^")));
+assertEquals("[\n 1,\n 2,\n [\n 3,\n [\n 4\n ],\n 5\n ],\n 6,\n 7\n]",
+ JSON.stringify([1, 2, [3, [4], 5], 6, 7], null, 1));
+assertEquals("[]", JSON.stringify([], null, 1));
+assertEquals("[1,2,[3,[4],5],6,7]",
+ JSON.stringify([1, 2, [3, [4], 5], 6, 7], null));
+assertEquals("[2,4,[6,[8],10],12,14]",
+ JSON.stringify([1, 2, [3, [4], 5], 6, 7], DoubleNumbers));
+
+var circular = [1, 2, 3];
+circular[2] = circular;
+assertThrows(function () { JSON.stringify(circular); }, TypeError);
+
+var singleton = [];
+var multiOccurrence = [singleton, singleton, singleton];
+assertEquals("[[],[],[]]", JSON.stringify(multiOccurrence));
+
+assertEquals('{"x":5,"y":6}', JSON.stringify({x:5,y:6}));
+assertEquals('{"x":5}', JSON.stringify({x:5,y:6}, ['x']));
+assertEquals('{\n "a": "b",\n "c": "d"\n}',
+ JSON.stringify({a:"b",c:"d"}, null, 1));
+assertEquals('{"y":6,"x":5}', JSON.stringify({x:5,y:6}, ['y', 'x']));
+
+assertEquals(undefined, JSON.stringify(undefined));
+assertEquals(undefined, JSON.stringify(function () { }));
}
+function deepObjectEquals(a, b) {
+ var aProps = [];
+ for (var key in a)
+ aProps.push(key);
+ var bProps = [];
+ for (var key in b)
+ bProps.push(key);
+ aProps.sort();
+ bProps.sort();
+ if (!deepEquals(aProps, bProps))
+ return false;
+ for (var i = 0; i < aProps.length; i++) {
+ if (!deepEquals(a[aProps[i]], b[aProps[i]]))
+ return false;
+ }
+ return true;
+}
+
+
function deepEquals(a, b) {
if (a == b) return true;
if (typeof a == "number" && typeof b == "number" && isNaN(a) && isNaN(b)) {
}
}
return true;
+ } else {
+ return deepObjectEquals(a, b);
}
- return false;
}
}
-function assertThrows(code) {
+function assertThrows(code, type_opt, cause_opt) {
var threwException = true;
try {
- eval(code);
+ if (typeof code == 'function') {
+ code();
+ } else {
+ eval(code);
+ }
threwException = false;
} catch (e) {
+ if (typeof type_opt == 'function')
+ assertInstanceof(e, type_opt);
+ if (arguments.length >= 3)
+ assertEquals(e.type, cause_opt);
// Do nothing.
}
if (!threwException) assertTrue(false, "did not throw exception");
set TARGET_DIR=%2
set PYTHON="..\..\..\third_party\python_24\python.exe"
if not exist %PYTHON% set PYTHON=python.exe
-%PYTHON% ..\js2c.py %TARGET_DIR%\natives.cc %TARGET_DIR%\natives-empty.cc CORE %SOURCE_DIR%\macros.py %SOURCE_DIR%\runtime.js %SOURCE_DIR%\v8natives.js %SOURCE_DIR%\array.js %SOURCE_DIR%\string.js %SOURCE_DIR%\uri.js %SOURCE_DIR%\math.js %SOURCE_DIR%\messages.js %SOURCE_DIR%\apinatives.js %SOURCE_DIR%\debug-delay.js %SOURCE_DIR%\mirror-delay.js %SOURCE_DIR%\date-delay.js %SOURCE_DIR%\regexp-delay.js
+%PYTHON% ..\js2c.py %TARGET_DIR%\natives.cc %TARGET_DIR%\natives-empty.cc CORE %SOURCE_DIR%\macros.py %SOURCE_DIR%\runtime.js %SOURCE_DIR%\v8natives.js %SOURCE_DIR%\array.js %SOURCE_DIR%\string.js %SOURCE_DIR%\uri.js %SOURCE_DIR%\math.js %SOURCE_DIR%\messages.js %SOURCE_DIR%\apinatives.js %SOURCE_DIR%\debug-delay.js %SOURCE_DIR%\mirror-delay.js %SOURCE_DIR%\date-delay.js %SOURCE_DIR%\regexp-delay.js %SOURCE_DIR%\json-delay.js
RelativePath="..\..\src\regexp-delay.js"
>
</File>
+ <File
+ RelativePath="..\..\src\json-delay.js"
+ >
+ </File>
<File
RelativePath="..\..\src\runtime.js"
>
Name="VCCustomBuildTool"
Description="Processing js files..."
CommandLine=".\js2c.cmd ..\..\src "$(IntDir)\DerivedSources""
- AdditionalDependencies="..\..\src\macros.py;..\..\src\runtime.js;..\..\src\v8natives.js;..\..\src\array.js;..\..\src\string.js;..\..\src\uri.js;..\..\src\math.js;..\..\src\messages.js;..\..\src\apinatives.js;..\..\src\debug-delay.js;..\..\src\mirror-delay.js;..\..\src\date-delay.js;..\..\src\regexp-delay.js"
+ AdditionalDependencies="..\..\src\macros.py;..\..\src\runtime.js;..\..\src\v8natives.js;..\..\src\array.js;..\..\src\string.js;..\..\src\uri.js;..\..\src\math.js;..\..\src\messages.js;..\..\src\apinatives.js;..\..\src\debug-delay.js;..\..\src\mirror-delay.js;..\..\src\date-delay.js;..\..\src\regexp-delay.js;..\..\src\json-delay.js"
Outputs="$(IntDir)\DerivedSources\natives.cc;$(IntDir)\DerivedSources\natives-empty.cc"
/>
</FileConfiguration>
Name="VCCustomBuildTool"
Description="Processing js files..."
CommandLine=".\js2c.cmd ..\..\src "$(IntDir)\DerivedSources""
- AdditionalDependencies="..\..\src\macros.py;..\..\src\runtime.js;..\..\src\v8natives.js;..\..\src\array.js;..\..\src\string.js;..\..\src\uri.js;..\..\src\math.js;..\..\src\messages.js;..\..\src\apinatives.js;..\..\src\debug-delay.js;..\..\src\mirror-delay.js;..\..\src\date-delay.js;..\..\src\regexp-delay.js"
+ AdditionalDependencies="..\..\src\macros.py;..\..\src\runtime.js;..\..\src\v8natives.js;..\..\src\array.js;..\..\src\string.js;..\..\src\uri.js;..\..\src\math.js;..\..\src\messages.js;..\..\src\apinatives.js;..\..\src\debug-delay.js;..\..\src\mirror-delay.js;..\..\src\date-delay.js;..\..\src\regexp-delay.js;..\..\src\json-delay.js"
Outputs="$(IntDir)\DerivedSources\natives.cc;$(IntDir)\DerivedSources\natives-empty.cc"
/>
</FileConfiguration>