Push version 1.2.1 to trunk.
Added EcmaScript 5 JSON object.
Fix bug in preemption support on ARM.
git-svn-id: http://v8.googlecode.com/svn/trunk@1797 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/SConscript b/src/SConscript
index 97fb7d6..b0a2933 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -53,20 +53,22 @@
'v8.cc', 'v8threads.cc', 'variables.cc', 'virtual-frame.cc', 'zone.cc'
],
'arch:arm': [
- 'assembler-arm.cc', 'builtins-arm.cc', 'codegen-arm.cc', 'cpu-arm.cc',
- 'disasm-arm.cc', 'debug-arm.cc', 'frames-arm.cc', 'ic-arm.cc',
- 'jump-target-arm.cc', 'macro-assembler-arm.cc',
- 'regexp-macro-assembler-arm.cc', 'register-allocator-arm.cc',
- 'stub-cache-arm.cc', 'virtual-frame-arm.cc'
+ 'arm/assembler-arm.cc', 'arm/builtins-arm.cc',
+ 'arm/codegen-arm.cc', 'arm/cpu-arm.cc', 'arm/disasm-arm.cc',
+ 'arm/debug-arm.cc', 'arm/frames-arm.cc', 'arm/ic-arm.cc',
+ 'arm/jump-target-arm.cc', 'arm/macro-assembler-arm.cc',
+ 'arm/register-allocator-arm.cc', 'arm/stub-cache-arm.cc',
+ 'arm/regexp-macro-assembler-arm.cc', 'arm/virtual-frame-arm.cc'
],
'arch:ia32': [
- 'assembler-ia32.cc', 'builtins-ia32.cc', 'codegen-ia32.cc',
- 'cpu-ia32.cc', 'disasm-ia32.cc', 'debug-ia32.cc', 'frames-ia32.cc',
- 'ic-ia32.cc', 'jump-target-ia32.cc', 'macro-assembler-ia32.cc',
- 'regexp-macro-assembler-ia32.cc', 'register-allocator-ia32.cc',
- 'stub-cache-ia32.cc', 'virtual-frame-ia32.cc'
+ 'ia32/assembler-ia32.cc', 'ia32/builtins-ia32.cc',
+ 'ia32/codegen-ia32.cc', 'ia32/cpu-ia32.cc', 'ia32/disasm-ia32.cc',
+ 'ia32/debug-ia32.cc', 'ia32/frames-ia32.cc', 'ia32/ic-ia32.cc',
+ 'ia32/jump-target-ia32.cc', 'ia32/macro-assembler-ia32.cc',
+ 'ia32/register-allocator-ia32.cc', 'ia32/stub-cache-ia32.cc',
+ 'ia32/regexp-macro-assembler-ia32.cc', 'ia32/virtual-frame-ia32.cc'
],
- 'simulator:arm': ['simulator-arm.cc'],
+ 'simulator:arm': ['arm/simulator-arm.cc'],
'os:freebsd': ['platform-freebsd.cc', 'platform-posix.cc'],
'os:linux': ['platform-linux.cc', 'platform-posix.cc'],
'os:android': ['platform-linux.cc', 'platform-posix.cc'],
@@ -121,6 +123,7 @@
mirror-delay.js
date-delay.js
regexp-delay.js
+json-delay.js
'''.split()
diff --git a/src/api.cc b/src/api.cc
index 449926c..860317d 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -2422,7 +2422,7 @@
const char* v8::V8::GetVersion() {
- return "1.2.0";
+ return "1.2.1";
}
@@ -3264,7 +3264,10 @@
bool message_handler_thread) {
EnsureInitialized("v8::Debug::SetMessageHandler");
ENTER_V8;
- i::Debugger::SetMessageHandler(handler, message_handler_thread);
+ // Message handler thread not supported any more. Parameter temporally left in
+ // the API for client compatability reasons.
+ CHECK(!message_handler_thread);
+ i::Debugger::SetMessageHandler(handler);
}
diff --git a/src/assembler-arm-inl.h b/src/arm/assembler-arm-inl.h
similarity index 99%
rename from src/assembler-arm-inl.h
rename to src/arm/assembler-arm-inl.h
index 315605e..65757e7 100644
--- a/src/assembler-arm-inl.h
+++ b/src/arm/assembler-arm-inl.h
@@ -37,7 +37,7 @@
#ifndef V8_ASSEMBLER_ARM_INL_H_
#define V8_ASSEMBLER_ARM_INL_H_
-#include "assembler-arm.h"
+#include "arm/assembler-arm.h"
#include "cpu.h"
diff --git a/src/assembler-arm.cc b/src/arm/assembler-arm.cc
similarity index 99%
rename from src/assembler-arm.cc
rename to src/arm/assembler-arm.cc
index ba7638e..191c865 100644
--- a/src/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -36,7 +36,7 @@
#include "v8.h"
-#include "assembler-arm-inl.h"
+#include "arm/assembler-arm-inl.h"
#include "serialize.h"
namespace v8 { namespace internal {
diff --git a/src/assembler-arm.h b/src/arm/assembler-arm.h
similarity index 96%
rename from src/assembler-arm.h
rename to src/arm/assembler-arm.h
index f965ebd..5edccbc 100644
--- a/src/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -164,23 +164,23 @@
// Condition field in instructions
enum Condition {
- eq = 0 << 28,
- ne = 1 << 28,
- cs = 2 << 28,
- hs = 2 << 28,
- cc = 3 << 28,
- lo = 3 << 28,
- mi = 4 << 28,
- pl = 5 << 28,
- vs = 6 << 28,
- vc = 7 << 28,
- hi = 8 << 28,
- ls = 9 << 28,
- ge = 10 << 28,
- lt = 11 << 28,
- gt = 12 << 28,
- le = 13 << 28,
- al = 14 << 28
+ eq = 0 << 28, // Z set equal.
+ ne = 1 << 28, // Z clear not equal.
+ cs = 2 << 28, // C set unsigned higher or same.
+ hs = 2 << 28, // C set unsigned higher or same.
+ cc = 3 << 28, // C clear unsigned lower.
+ lo = 3 << 28, // C clear unsigned lower.
+ mi = 4 << 28, // N set negative.
+ pl = 5 << 28, // N clear positive or zero.
+ vs = 6 << 28, // V set overflow.
+ vc = 7 << 28, // V clear no overflow.
+ hi = 8 << 28, // C set, Z clear unsigned higher.
+ ls = 9 << 28, // C clear or Z set unsigned lower or same.
+ ge = 10 << 28, // N == V greater or equal.
+ lt = 11 << 28, // N != V less than.
+ gt = 12 << 28, // Z clear, N == V greater than.
+ le = 13 << 28, // Z set or N != V less then or equal
+ al = 14 << 28 // always.
};
diff --git a/src/builtins-arm.cc b/src/arm/builtins-arm.cc
similarity index 96%
rename from src/builtins-arm.cc
rename to src/arm/builtins-arm.cc
index 58eeca8..519c04a 100644
--- a/src/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -417,15 +417,35 @@
__ push(r0);
__ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_JS);
- // Eagerly check for stack-overflow before starting to push the arguments.
- // r0: number of arguments
- Label okay;
+ Label no_preemption, retry_preemption;
+ __ bind(&retry_preemption);
ExternalReference stack_guard_limit_address =
ExternalReference::address_of_stack_guard_limit();
__ mov(r2, Operand(stack_guard_limit_address));
__ ldr(r2, MemOperand(r2));
+ __ cmp(sp, r2);
+ __ b(hi, &no_preemption);
+
+ // We have encountered a preemption or stack overflow already before we push
+ // the array contents. Save r0 which is the Smi-tagged length of the array.
+ __ push(r0);
+
+ // Runtime routines expect at least one argument, so give it a Smi.
+ __ mov(r0, Operand(Smi::FromInt(0)));
+ __ push(r0);
+ __ CallRuntime(Runtime::kStackGuard, 1);
+
+ // Since we returned, it wasn't a stack overflow. Restore r0 and try again.
+ __ pop(r0);
+ __ b(&retry_preemption);
+
+ __ bind(&no_preemption);
+
+ // Eagerly check for stack-overflow before starting to push the arguments.
+ // r0: number of arguments.
+ // r2: stack limit.
+ Label okay;
__ sub(r2, sp, r2);
- __ sub(r2, r2, Operand(3 * kPointerSize)); // limit, index, receiver
__ cmp(r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
__ b(hi, &okay);
diff --git a/src/codegen-arm.cc b/src/arm/codegen-arm.cc
similarity index 99%
rename from src/codegen-arm.cc
rename to src/arm/codegen-arm.cc
index 9337454..57e98c1 100644
--- a/src/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -4596,7 +4596,9 @@
__ ldr(ip, MemOperand(ip));
__ cmp(sp, Operand(ip));
__ b(hs, &within_limit);
- // Do tail-call to runtime routine.
+ // Do tail-call to runtime routine. Runtime routines expect at least one
+ // argument, so give it a Smi.
+ __ mov(r0, Operand(Smi::FromInt(0)));
__ push(r0);
__ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
__ bind(&within_limit);
diff --git a/src/codegen-arm.h b/src/arm/codegen-arm.h
similarity index 100%
rename from src/codegen-arm.h
rename to src/arm/codegen-arm.h
diff --git a/src/constants-arm.h b/src/arm/constants-arm.h
similarity index 100%
rename from src/constants-arm.h
rename to src/arm/constants-arm.h
diff --git a/src/cpu-arm.cc b/src/arm/cpu-arm.cc
similarity index 100%
rename from src/cpu-arm.cc
rename to src/arm/cpu-arm.cc
diff --git a/src/debug-arm.cc b/src/arm/debug-arm.cc
similarity index 100%
rename from src/debug-arm.cc
rename to src/arm/debug-arm.cc
diff --git a/src/disasm-arm.cc b/src/arm/disasm-arm.cc
similarity index 100%
rename from src/disasm-arm.cc
rename to src/arm/disasm-arm.cc
diff --git a/src/frames-arm.cc b/src/arm/frames-arm.cc
similarity index 98%
rename from src/frames-arm.cc
rename to src/arm/frames-arm.cc
index 121fb75..d26198a 100644
--- a/src/frames-arm.cc
+++ b/src/arm/frames-arm.cc
@@ -28,7 +28,7 @@
#include "v8.h"
#include "frames-inl.h"
-#include "assembler-arm-inl.h"
+#include "arm/assembler-arm-inl.h"
namespace v8 { namespace internal {
diff --git a/src/frames-arm.h b/src/arm/frames-arm.h
similarity index 100%
rename from src/frames-arm.h
rename to src/arm/frames-arm.h
diff --git a/src/ic-arm.cc b/src/arm/ic-arm.cc
similarity index 95%
rename from src/ic-arm.cc
rename to src/arm/ic-arm.cc
index ad6eb2c..e418556 100644
--- a/src/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -127,27 +127,20 @@
}
-// 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);
}
@@ -284,9 +277,9 @@
__ 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.
@@ -470,7 +463,7 @@
__ bind(&probe);
GenerateDictionaryLoad(masm, &miss, r1, r0);
- GenerateCheckNonFunctionOrLoaded(masm, &miss, r0, r1);
+ GenerateCheckNonObjectOrLoaded(masm, &miss, r0, r1);
__ Ret();
// Global object access: Check access rights.
diff --git a/src/jump-target-arm.cc b/src/arm/jump-target-arm.cc
similarity index 100%
rename from src/jump-target-arm.cc
rename to src/arm/jump-target-arm.cc
diff --git a/src/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
similarity index 100%
rename from src/macro-assembler-arm.cc
rename to src/arm/macro-assembler-arm.cc
diff --git a/src/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
similarity index 100%
rename from src/macro-assembler-arm.h
rename to src/arm/macro-assembler-arm.h
diff --git a/src/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc
similarity index 97%
rename from src/regexp-macro-assembler-arm.cc
rename to src/arm/regexp-macro-assembler-arm.cc
index bcfddf6..bf07f0e 100644
--- a/src/regexp-macro-assembler-arm.cc
+++ b/src/arm/regexp-macro-assembler-arm.cc
@@ -28,7 +28,7 @@
#include "v8.h"
#include "ast.h"
#include "regexp-macro-assembler.h"
-#include "regexp-macro-assembler-arm.h"
+#include "arm/regexp-macro-assembler-arm.h"
namespace v8 { namespace internal {
diff --git a/src/regexp-macro-assembler-arm.h b/src/arm/regexp-macro-assembler-arm.h
similarity index 100%
rename from src/regexp-macro-assembler-arm.h
rename to src/arm/regexp-macro-assembler-arm.h
diff --git a/src/register-allocator-arm.cc b/src/arm/register-allocator-arm.cc
similarity index 100%
rename from src/register-allocator-arm.cc
rename to src/arm/register-allocator-arm.cc
diff --git a/src/simulator-arm.cc b/src/arm/simulator-arm.cc
similarity index 99%
rename from src/simulator-arm.cc
rename to src/arm/simulator-arm.cc
index 7d96b3a..9737e95 100644
--- a/src/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -30,8 +30,8 @@
#include "v8.h"
#include "disasm.h"
-#include "constants-arm.h"
-#include "simulator-arm.h"
+#include "arm/constants-arm.h"
+#include "arm/simulator-arm.h"
#if !defined(__arm__)
diff --git a/src/simulator-arm.h b/src/arm/simulator-arm.h
similarity index 100%
rename from src/simulator-arm.h
rename to src/arm/simulator-arm.h
diff --git a/src/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
similarity index 100%
rename from src/stub-cache-arm.cc
rename to src/arm/stub-cache-arm.cc
diff --git a/src/virtual-frame-arm.cc b/src/arm/virtual-frame-arm.cc
similarity index 98%
rename from src/virtual-frame-arm.cc
rename to src/arm/virtual-frame-arm.cc
index b794d8b..43100f1 100644
--- a/src/virtual-frame-arm.cc
+++ b/src/arm/virtual-frame-arm.cc
@@ -71,6 +71,16 @@
}
+void VirtualFrame::SyncRange(int begin, int end) {
+ // All elements are in memory on ARM (ie, synced).
+#ifdef DEBUG
+ for (int i = begin; i <= end; i++) {
+ ASSERT(elements_[i].is_synced());
+ }
+#endif
+}
+
+
void VirtualFrame::MergeTo(VirtualFrame* expected) {
Comment cmnt(masm_, "[ Merge frame");
// We should always be merging the code generator's current frame to an
diff --git a/src/virtual-frame-arm.h b/src/arm/virtual-frame-arm.h
similarity index 100%
rename from src/virtual-frame-arm.h
rename to src/arm/virtual-frame-arm.h
diff --git a/src/ast.cc b/src/ast.cc
index 1a6010a..d19e3b3 100644
--- a/src/ast.cc
+++ b/src/ast.cc
@@ -152,6 +152,27 @@
}
+bool ObjectLiteral::IsValidJSON() {
+ int length = properties()->length();
+ for (int i = 0; i < length; i++) {
+ Property* prop = properties()->at(i);
+ if (!prop->value()->IsValidJSON())
+ return false;
+ }
+ return true;
+}
+
+
+bool ArrayLiteral::IsValidJSON() {
+ int length = values()->length();
+ for (int i = 0; i < length; i++) {
+ if (!values()->at(i)->IsValidJSON())
+ return false;
+ }
+ return true;
+}
+
+
void TargetCollector::AddTarget(BreakTarget* target) {
// Add the label to the collector, but discard duplicates.
int length = targets_->length();
diff --git a/src/ast.h b/src/ast.h
index b496816..6a2f671 100644
--- a/src/ast.h
+++ b/src/ast.h
@@ -155,6 +155,7 @@
public:
virtual Expression* AsExpression() { return this; }
+ virtual bool IsValidJSON() { return false; }
virtual bool IsValidLeftHandSide() { return false; }
// Mark the expression as being compiled as an expression
@@ -625,6 +626,8 @@
return handle_.is_identical_to(other->handle_);
}
+ virtual bool IsValidJSON() { return true; }
+
// Identity testers.
bool IsNull() const { return handle_.is_identical_to(Factory::null_value()); }
bool IsTrue() const { return handle_.is_identical_to(Factory::true_value()); }
@@ -653,6 +656,8 @@
// constants and simple object and array literals.
bool is_simple() const { return is_simple_; }
+ virtual bool IsValidJSON() { return true; }
+
int depth() const { return depth_; }
private:
@@ -704,6 +709,7 @@
virtual ObjectLiteral* AsObjectLiteral() { return this; }
virtual void Accept(AstVisitor* v);
+ virtual bool IsValidJSON();
Handle<FixedArray> constant_properties() const {
return constant_properties_;
@@ -751,6 +757,7 @@
virtual void Accept(AstVisitor* v);
virtual ArrayLiteral* AsArrayLiteral() { return this; }
+ virtual bool IsValidJSON();
Handle<FixedArray> literals() const { return literals_; }
ZoneList<Expression*>* values() const { return values_; }
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index eebec74..c434207 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -530,7 +530,7 @@
global_context()->function_instance_map()->set_prototype(*empty_function);
// Allocate the function map first and then patch the prototype later
- Handle<Map> empty_fm = Factory::CopyMap(fm);
+ Handle<Map> empty_fm = Factory::CopyMapDropDescriptors(fm);
empty_fm->set_instance_descriptors(*function_map_descriptors);
empty_fm->set_prototype(global_context()->object_function()->prototype());
empty_function->set_map(*empty_fm);
@@ -741,6 +741,19 @@
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
@@ -1068,6 +1081,10 @@
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
@@ -1416,7 +1433,7 @@
Handle<DescriptorArray> function_map_descriptors =
ComputeFunctionInstanceDescriptor(false, true);
- Handle<Map> fm = Factory::CopyMap(Top::function_map());
+ Handle<Map> fm = Factory::CopyMapDropDescriptors(Top::function_map());
fm->set_instance_descriptors(*function_map_descriptors);
Top::context()->global_context()->set_function_map(*fm);
}
diff --git a/src/codegen.h b/src/codegen.h
index 54fe330..e9a5edd 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -77,9 +77,9 @@
#ifdef ARM
-#include "codegen-arm.h"
+#include "arm/codegen-arm.h"
#else
-#include "codegen-ia32.h"
+#include "ia32/codegen-ia32.h"
#endif
namespace v8 { namespace internal {
diff --git a/src/compiler.cc b/src/compiler.cc
index 62e838e..c16b938 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -80,8 +80,20 @@
}
+static bool IsValidJSON(FunctionLiteral* lit) {
+ if (!lit->body()->length() == 1)
+ return false;
+ Statement* stmt = lit->body()->at(0);
+ if (stmt->AsExpressionStatement() == NULL)
+ return false;
+ Expression *expr = stmt->AsExpressionStatement()->expression();
+ return expr->IsValidJSON();
+}
+
+
static Handle<JSFunction> MakeFunction(bool is_global,
bool is_eval,
+ bool is_json,
Handle<Script> script,
Handle<Context> context,
v8::Extension* extension,
@@ -109,6 +121,19 @@
return Handle<JSFunction>::null();
}
+ // When parsing JSON we do an ordinary parse and then afterwards
+ // check the AST to ensure it was well-formed. If not we give a
+ // syntax error.
+ if (is_json && !IsValidJSON(lit)) {
+ HandleScope scope;
+ Handle<JSArray> args = Factory::NewJSArray(1);
+ Handle<Object> source(script->source());
+ SetElement(args, 0, source);
+ Handle<Object> result = Factory::NewSyntaxError("invalid_json", args);
+ Top::Throw(*result, NULL);
+ return Handle<JSFunction>::null();
+ }
+
// Measure how long it takes to do the compilation; only take the
// rest of the function into account to avoid overlap with the
// parsing statistics.
@@ -215,6 +240,7 @@
// Compile the function and add it to the cache.
result = MakeFunction(true,
false,
+ false,
script,
Handle<Context>::null(),
extension,
@@ -237,7 +263,8 @@
Handle<JSFunction> Compiler::CompileEval(Handle<String> source,
Handle<Context> context,
int line_offset,
- bool is_global) {
+ bool is_global,
+ bool is_json) {
int source_length = source->length();
Counters::total_eval_size.Increment(source_length);
Counters::total_compile_size.Increment(source_length);
@@ -256,7 +283,13 @@
// Create a script object describing the script to be compiled.
Handle<Script> script = Factory::NewScript(source);
script->set_line_offset(Smi::FromInt(line_offset));
- result = MakeFunction(is_global, true, script, context, NULL, NULL);
+ result = MakeFunction(is_global,
+ true,
+ is_json,
+ script,
+ context,
+ NULL,
+ NULL);
if (!result.is_null()) {
CompilationCache::PutEval(source, context, entry, result);
}
diff --git a/src/compiler.h b/src/compiler.h
index 4f589b7..8abe130 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -60,7 +60,8 @@
static Handle<JSFunction> CompileEval(Handle<String> source,
Handle<Context> context,
int line_offset,
- bool is_global);
+ bool is_global,
+ bool is_json);
// Compile from function info (used for lazy compilation). Returns
// true on success and false if the compilation resulted in a stack
diff --git a/src/contexts.h b/src/contexts.h
index 3c25bd3..ed4b1cf 100644
--- a/src/contexts.h
+++ b/src/contexts.h
@@ -64,6 +64,7 @@
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) \
@@ -186,6 +187,7 @@
OBJECT_FUNCTION_INDEX,
ARRAY_FUNCTION_INDEX,
DATE_FUNCTION_INDEX,
+ JSON_OBJECT_INDEX,
REGEXP_FUNCTION_INDEX,
CREATE_DATE_FUN_INDEX,
TO_NUMBER_FUN_INDEX,
diff --git a/src/date-delay.js b/src/date-delay.js
index 2421e5b..dbb9c2c 100644
--- a/src/date-delay.js
+++ b/src/date-delay.js
@@ -985,6 +985,25 @@
}
+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() {
@@ -1044,7 +1063,9 @@
"toGMTString", DateToGMTString,
"toUTCString", DateToUTCString,
"getYear", DateGetYear,
- "setYear", DateSetYear
+ "setYear", DateSetYear,
+ "toISOString", DateToISOString,
+ "toJSON", DateToJSON
));
}
diff --git a/src/debug-agent.cc b/src/debug-agent.cc
index 9838746..0fab188 100644
--- a/src/debug-agent.cc
+++ b/src/debug-agent.cc
@@ -107,7 +107,7 @@
// Create a new session and hook up the debug message handler.
session_ = new DebuggerAgentSession(this, client);
- v8::Debug::SetMessageHandler(DebuggerAgentMessageHandler, this);
+ v8::Debug::SetMessageHandler(DebuggerAgentMessageHandler);
session_->Start();
}
diff --git a/src/debug-delay.js b/src/debug-delay.js
index 6cb5e7f..961f304 100644
--- a/src/debug-delay.js
+++ b/src/debug-delay.js
@@ -1133,7 +1133,7 @@
try {
try {
// Convert the JSON string to an object.
- request = %CompileString('(' + json_request + ')', 0)();
+ request = %CompileString('(' + json_request + ')', 0, false)();
// Create an initial response.
response = this.createResponse(request);
diff --git a/src/debug.cc b/src/debug.cc
index 32a96a8..239a373 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -1420,16 +1420,13 @@
bool Debugger::compiling_natives_ = false;
bool Debugger::is_loading_debugger_ = false;
bool Debugger::never_unload_debugger_ = false;
-DebugMessageThread* Debugger::message_thread_ = NULL;
v8::Debug::MessageHandler Debugger::message_handler_ = NULL;
bool Debugger::message_handler_cleared_ = false;
v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
int Debugger::host_dispatch_micros_ = 100 * 1000;
DebuggerAgent* Debugger::agent_ = NULL;
-LockingMessageQueue Debugger::command_queue_(kQueueInitialSize);
-LockingMessageQueue Debugger::message_queue_(kQueueInitialSize);
+LockingCommandMessageQueue Debugger::command_queue_(kQueueInitialSize);
Semaphore* Debugger::command_received_ = OS::CreateSemaphore(0);
-Semaphore* Debugger::message_received_ = OS::CreateSemaphore(0);
Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
@@ -1818,7 +1815,7 @@
// Notify the debugger that a debug event has occurred unless auto continue is
// active in which case no event is send.
if (!auto_continue) {
- bool success = SendEventMessage(event_data);
+ bool success = InvokeMessageHandlerWithEvent(event_data);
if (!success) {
// If failed to notify debugger just continue running.
return;
@@ -1845,7 +1842,7 @@
StackGuard::Continue(DEBUGCOMMAND);
// Get the command from the queue.
- Message command = command_queue_.Get();
+ CommandMessage command = command_queue_.Get();
Logger::DebugTag("Got request from command queue, in interactive loop.");
if (!Debugger::IsDebuggerActive()) {
// Delete command text and user data.
@@ -1900,7 +1897,7 @@
}
// Return the result.
- SendMessage(Message::NewOutput(response, command.client_data()));
+ InvokeMessageHandler(response, command.client_data());
// Return from debug event processing if either the VM is put into the
// runnning state (through a continue command) or auto continue is active
@@ -1946,17 +1943,11 @@
}
-void Debugger::SetMessageHandler(v8::Debug::MessageHandler handler,
- bool message_handler_thread) {
+void Debugger::SetMessageHandler(v8::Debug::MessageHandler handler) {
ScopedLock with(debugger_access_);
message_handler_ = handler;
- if (handler != NULL) {
- if (!message_thread_ && message_handler_thread) {
- message_thread_ = new DebugMessageThread();
- message_thread_->Start();
- }
- } else {
+ if (handler == NULL) {
// Indicate that the message handler was recently cleared.
message_handler_cleared_ = true;
@@ -1980,34 +1971,25 @@
// public API. Messages are kept internally as Vector<uint16_t> strings, which
// are allocated in various places and deallocated by the calling function
// sometime after this call.
-void Debugger::InvokeMessageHandler(Message message) {
+void Debugger::InvokeMessageHandler(v8::Handle<v8::String> output,
+ v8::Debug::ClientData* data) {
ScopedLock with(debugger_access_);
if (message_handler_ != NULL) {
- message_handler_(message.text().start(),
- message.text().length(),
- message.client_data());
+ Vector<uint16_t> text = Vector<uint16_t>::New(output->Length());
+ output->Write(text.start(), 0, output->Length());
+
+ message_handler_(text.start(),
+ text.length(),
+ data);
+
+ text.Dispose();
}
- message.Dispose();
+ delete data;
}
-void Debugger::SendMessage(Message message) {
- if (message_thread_ == NULL) {
- // If there is no message thread just invoke the message handler from the
- // V8 thread.
- InvokeMessageHandler(message);
- } else {
- // Put the message coming from V8 on the queue. The text and user data will
- // be destroyed by the message thread.
- Logger::DebugTag("Put message on event message_queue.");
- message_queue_.Put(message);
- message_received_->Signal();
- }
-}
-
-
-bool Debugger::SendEventMessage(Handle<Object> event_data) {
+bool Debugger::InvokeMessageHandlerWithEvent(Handle<Object> event_data) {
v8::HandleScope scope;
// Call toJSONProtocol on the debug event object.
v8::Local<v8::Object> api_event_data =
@@ -2024,11 +2006,10 @@
if (FLAG_trace_debug_json) {
PrintLn(json_event_string);
}
- SendMessage(Message::NewOutput(
- json_event_string,
- NULL /* no user data since there was no request */));
+ InvokeMessageHandler(json_event_string,
+ NULL /* no user data since there was no request */);
} else {
- SendMessage(Message::NewEmptyMessage());
+ InvokeMessageHandler(v8::String::Empty(), NULL);
}
} else {
PrintLn(try_catch.Exception());
@@ -2041,13 +2022,11 @@
// Puts a command coming from the public API on the queue. Creates
// a copy of the command string managed by the debugger. Up to this
// point, the command data was managed by the API client. Called
-// by the API client thread. This is where the API client hands off
-// processing of the command to the DebugMessageThread thread.
-// The new copy of the command is destroyed in HandleCommand().
+// by the API client thread.
void Debugger::ProcessCommand(Vector<const uint16_t> command,
v8::Debug::ClientData* client_data) {
// Need to cast away const.
- Message message = Message::NewCommand(
+ CommandMessage message = CommandMessage::New(
Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
command.length()),
client_data);
@@ -2122,99 +2101,51 @@
}
-void Debugger::TearDown() {
- if (message_thread_ != NULL) {
- message_thread_->Stop();
- delete message_thread_;
- message_thread_ = NULL;
- }
+CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
+ client_data_(NULL) {
}
-void DebugMessageThread::Run() {
- // Sends debug events to an installed debugger message callback.
- while (keep_running_) {
- // Wait and Get are paired so that semaphore count equals queue length.
- Debugger::message_received_->Wait();
- Logger::DebugTag("Get message from event message_queue.");
- Message message = Debugger::message_queue_.Get();
- if (message.text().length() > 0) {
- Debugger::InvokeMessageHandler(message);
- } else {
- message.Dispose();
- }
- }
-}
-
-
-void DebugMessageThread::Stop() {
- keep_running_ = false;
- Debugger::SendMessage(Message::NewEmptyMessage());
- Join();
-}
-
-
-Message::Message() : text_(Vector<uint16_t>::empty()),
- client_data_(NULL) {
-}
-
-
-Message::Message(const Vector<uint16_t>& text,
- v8::Debug::ClientData* data)
+CommandMessage::CommandMessage(const Vector<uint16_t>& text,
+ v8::Debug::ClientData* data)
: text_(text),
client_data_(data) {
}
-Message::~Message() {
+CommandMessage::~CommandMessage() {
}
-void Message::Dispose() {
+void CommandMessage::Dispose() {
text_.Dispose();
delete client_data_;
client_data_ = NULL;
}
-Message Message::NewCommand(const Vector<uint16_t>& command,
- v8::Debug::ClientData* data) {
- return Message(command.Clone(), data);
+CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
+ v8::Debug::ClientData* data) {
+ return CommandMessage(command.Clone(), data);
}
-Message Message::NewOutput(v8::Handle<v8::String> output,
- v8::Debug::ClientData* data) {
- Vector<uint16_t> text;
- if (!output.IsEmpty()) {
- // Do not include trailing '\0'.
- text = Vector<uint16_t>::New(output->Length());
- output->Write(text.start(), 0, output->Length());
- }
- return Message(text, data);
+CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
+ size_(size) {
+ messages_ = NewArray<CommandMessage>(size);
}
-Message Message::NewEmptyMessage() {
- return Message();
-}
-
-
-MessageQueue::MessageQueue(int size) : start_(0), end_(0), size_(size) {
- messages_ = NewArray<Message>(size);
-}
-
-
-MessageQueue::~MessageQueue() {
+CommandMessageQueue::~CommandMessageQueue() {
while (!IsEmpty()) {
- Message m = Get();
+ CommandMessage m = Get();
m.Dispose();
}
DeleteArray(messages_);
}
-Message MessageQueue::Get() {
+CommandMessage CommandMessageQueue::Get() {
ASSERT(!IsEmpty());
int result = start_;
start_ = (start_ + 1) % size_;
@@ -2222,7 +2153,7 @@
}
-void MessageQueue::Put(const Message& message) {
+void CommandMessageQueue::Put(const CommandMessage& message) {
if ((end_ + 1) % size_ == start_) {
Expand();
}
@@ -2231,12 +2162,12 @@
}
-void MessageQueue::Expand() {
- MessageQueue new_queue(size_ * 2);
+void CommandMessageQueue::Expand() {
+ CommandMessageQueue new_queue(size_ * 2);
while (!IsEmpty()) {
new_queue.Put(Get());
}
- Message* array_to_free = messages_;
+ CommandMessage* array_to_free = messages_;
*this = new_queue;
new_queue.messages_ = array_to_free;
// Make the new_queue empty so that it doesn't call Dispose on any messages.
@@ -2245,38 +2176,39 @@
}
-LockingMessageQueue::LockingMessageQueue(int size) : queue_(size) {
+LockingCommandMessageQueue::LockingCommandMessageQueue(int size)
+ : queue_(size) {
lock_ = OS::CreateMutex();
}
-LockingMessageQueue::~LockingMessageQueue() {
+LockingCommandMessageQueue::~LockingCommandMessageQueue() {
delete lock_;
}
-bool LockingMessageQueue::IsEmpty() const {
+bool LockingCommandMessageQueue::IsEmpty() const {
ScopedLock sl(lock_);
return queue_.IsEmpty();
}
-Message LockingMessageQueue::Get() {
+CommandMessage LockingCommandMessageQueue::Get() {
ScopedLock sl(lock_);
- Message result = queue_.Get();
+ CommandMessage result = queue_.Get();
Logger::DebugEvent("Get", result.text());
return result;
}
-void LockingMessageQueue::Put(const Message& message) {
+void LockingCommandMessageQueue::Put(const CommandMessage& message) {
ScopedLock sl(lock_);
queue_.Put(message);
Logger::DebugEvent("Put", message.text());
}
-void LockingMessageQueue::Clear() {
+void LockingCommandMessageQueue::Clear() {
ScopedLock sl(lock_);
queue_.Clear();
}
diff --git a/src/debug.h b/src/debug.h
index ffd3da9..8a50cd2 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -405,70 +405,65 @@
// In addition to command text it may contain a pointer to some user data
// which are expected to be passed along with the command reponse to message
// handler.
-class Message {
+class CommandMessage {
public:
- static Message NewCommand(const Vector<uint16_t>& command,
+ static CommandMessage New(const Vector<uint16_t>& command,
v8::Debug::ClientData* data);
- static Message NewOutput(v8::Handle<v8::String> output,
- v8::Debug::ClientData* data);
- static Message NewEmptyMessage();
- Message();
- ~Message();
+ CommandMessage();
+ ~CommandMessage();
// Deletes user data and disposes of the text.
void Dispose();
Vector<uint16_t> text() const { return text_; }
v8::Debug::ClientData* client_data() const { return client_data_; }
private:
- Message(const Vector<uint16_t>& text,
- v8::Debug::ClientData* data);
+ CommandMessage(const Vector<uint16_t>& text,
+ v8::Debug::ClientData* data);
Vector<uint16_t> text_;
v8::Debug::ClientData* client_data_;
};
-// A Queue of Vector<uint16_t> objects. A thread-safe version is
-// LockingMessageQueue, based on this class.
-class MessageQueue BASE_EMBEDDED {
+// A Queue of CommandMessage objects. A thread-safe version is
+// LockingCommandMessageQueue, based on this class.
+class CommandMessageQueue BASE_EMBEDDED {
public:
- explicit MessageQueue(int size);
- ~MessageQueue();
+ explicit CommandMessageQueue(int size);
+ ~CommandMessageQueue();
bool IsEmpty() const { return start_ == end_; }
- Message Get();
- void Put(const Message& message);
+ CommandMessage Get();
+ void Put(const CommandMessage& message);
void Clear() { start_ = end_ = 0; } // Queue is empty after Clear().
private:
// Doubles the size of the message queue, and copies the messages.
void Expand();
- Message* messages_;
+ CommandMessage* messages_;
int start_;
int end_;
int size_; // The size of the queue buffer. Queue can hold size-1 messages.
};
-// LockingMessageQueue is a thread-safe circular buffer of Vector<uint16_t>
-// messages. The message data is not managed by LockingMessageQueue.
+// LockingCommandMessageQueue is a thread-safe circular buffer of CommandMessage
+// messages. The message data is not managed by LockingCommandMessageQueue.
// Pointers to the data are passed in and out. Implemented by adding a
-// Mutex to MessageQueue. Includes logging of all puts and gets.
-class LockingMessageQueue BASE_EMBEDDED {
+// Mutex to CommandMessageQueue. Includes logging of all puts and gets.
+class LockingCommandMessageQueue BASE_EMBEDDED {
public:
- explicit LockingMessageQueue(int size);
- ~LockingMessageQueue();
+ explicit LockingCommandMessageQueue(int size);
+ ~LockingCommandMessageQueue();
bool IsEmpty() const;
- Message Get();
- void Put(const Message& message);
+ CommandMessage Get();
+ void Put(const CommandMessage& message);
void Clear();
private:
- MessageQueue queue_;
+ CommandMessageQueue queue_;
Mutex* lock_;
- DISALLOW_COPY_AND_ASSIGN(LockingMessageQueue);
+ DISALLOW_COPY_AND_ASSIGN(LockingCommandMessageQueue);
};
-class DebugMessageThread;
-
class Debugger {
public:
static void DebugRequest(const uint16_t* json_request, int length);
@@ -503,21 +498,16 @@
Handle<Object> event_data,
bool auto_continue);
static void SetEventListener(Handle<Object> callback, Handle<Object> data);
- static void SetMessageHandler(v8::Debug::MessageHandler handler,
- bool message_handler_thread);
- static void TearDown();
+ static void SetMessageHandler(v8::Debug::MessageHandler handler);
static void SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
int period);
// Invoke the message handler function.
- static void InvokeMessageHandler(Message message);
-
- // Send a message to the message handler eiher through the message thread or
- // directly.
- static void SendMessage(Message message);
+ static void InvokeMessageHandler(v8::Handle<v8::String> output,
+ v8::Debug::ClientData* data);
// Send the JSON message for a debug event.
- static bool SendEventMessage(Handle<Object> event_data);
+ static bool InvokeMessageHandlerWithEvent(Handle<Object> event_data);
// Add a debugger command to the command queue.
static void ProcessCommand(Vector<const uint16_t> command,
@@ -568,7 +558,6 @@
static bool compiling_natives_; // Are we compiling natives?
static bool is_loading_debugger_; // Are we loading the debugger?
static bool never_unload_debugger_; // Can we unload the debugger?
- static DebugMessageThread* message_thread_;
static v8::Debug::MessageHandler message_handler_;
static bool message_handler_cleared_; // Was message handler cleared?
static v8::Debug::HostDispatchHandler host_dispatch_handler_;
@@ -577,32 +566,10 @@
static DebuggerAgent* agent_;
static const int kQueueInitialSize = 4;
- static LockingMessageQueue command_queue_;
- static LockingMessageQueue message_queue_;
+ static LockingCommandMessageQueue command_queue_;
static Semaphore* command_received_; // Signaled for each command received.
- static Semaphore* message_received_; // Signalled for each message send.
friend class EnterDebugger;
- friend class DebugMessageThread;
-};
-
-
-// Thread to read messages from the message queue and invoke the debug message
-// handler in another thread as the V8 thread. This thread is started if the
-// registration of the debug message handler requested to be called in a thread
-// seperate from the V8 thread.
-class DebugMessageThread: public Thread {
- public:
- DebugMessageThread() : keep_running_(true) {}
- virtual ~DebugMessageThread() {}
-
- // Main function of DebugMessageThread thread.
- void Run();
- void Stop();
-
- private:
- bool keep_running_;
- DISALLOW_COPY_AND_ASSIGN(DebugMessageThread);
};
diff --git a/src/execution.cc b/src/execution.cc
index 1d4d9ef..8fa059a 100644
--- a/src/execution.cc
+++ b/src/execution.cc
@@ -33,9 +33,9 @@
#include "codegen-inl.h"
#ifdef ARM
-#include "simulator-arm.h"
+#include "arm/simulator-arm.h"
#else // ia32
-#include "simulator-ia32.h"
+#include "ia32/simulator-ia32.h"
#endif
#include "debug.h"
diff --git a/src/factory.cc b/src/factory.cc
index c849ab7..c6b1d17 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -208,14 +208,14 @@
}
-Handle<Map> Factory::CopyMap(Handle<Map> src) {
- CALL_HEAP_FUNCTION(src->Copy(), Map);
+Handle<Map> Factory::CopyMapDropDescriptors(Handle<Map> src) {
+ CALL_HEAP_FUNCTION(src->CopyDropDescriptors(), Map);
}
Handle<Map> Factory::CopyMap(Handle<Map> src,
int extra_inobject_properties) {
- Handle<Map> copy = CopyMap(src);
+ Handle<Map> copy = CopyMapDropDescriptors(src);
// Check that we do not overflow the instance size when adding the
// extra inobject properties.
int instance_size_delta = extra_inobject_properties * kPointerSize;
diff --git a/src/factory.h b/src/factory.h
index 54f2089..6ac2706 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -153,7 +153,7 @@
static Handle<JSObject> NewFunctionPrototype(Handle<JSFunction> function);
- static Handle<Map> CopyMap(Handle<Map> map);
+ static Handle<Map> CopyMapDropDescriptors(Handle<Map> map);
// Copy the map adding more inobject properties if possible without
// overflowing the instance size.
diff --git a/src/frames-inl.h b/src/frames-inl.h
index cb03e2f..481b83b 100644
--- a/src/frames-inl.h
+++ b/src/frames-inl.h
@@ -30,9 +30,9 @@
#include "frames.h"
#ifdef ARM
-#include "frames-arm.h"
+#include "arm/frames-arm.h"
#else
-#include "frames-ia32.h"
+#include "ia32/frames-ia32.h"
#endif
diff --git a/src/handles.cc b/src/handles.cc
index 99161ce..773483d 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -627,9 +627,9 @@
}
-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)));
@@ -674,27 +674,39 @@
// 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::CopyMapDropTransitions(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
diff --git a/src/handles.h b/src/handles.h
index 9cc1db4..652d6c7 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -301,11 +301,11 @@
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:
diff --git a/src/heap.cc b/src/heap.cc
index a57884c..0775a5d 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -939,6 +939,7 @@
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;
}
@@ -1409,7 +1410,6 @@
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());
diff --git a/src/assembler-ia32-inl.h b/src/ia32/assembler-ia32-inl.h
similarity index 100%
rename from src/assembler-ia32-inl.h
rename to src/ia32/assembler-ia32-inl.h
diff --git a/src/assembler-ia32.cc b/src/ia32/assembler-ia32.cc
similarity index 100%
rename from src/assembler-ia32.cc
rename to src/ia32/assembler-ia32.cc
diff --git a/src/assembler-ia32.h b/src/ia32/assembler-ia32.h
similarity index 100%
rename from src/assembler-ia32.h
rename to src/ia32/assembler-ia32.h
diff --git a/src/builtins-ia32.cc b/src/ia32/builtins-ia32.cc
similarity index 100%
rename from src/builtins-ia32.cc
rename to src/ia32/builtins-ia32.cc
diff --git a/src/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
similarity index 99%
rename from src/codegen-ia32.cc
rename to src/ia32/codegen-ia32.cc
index fb2f8bf..2d6fe83 100644
--- a/src/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -5273,12 +5273,14 @@
// instruction.
ASSERT(value.is_register() && value.reg().is(eax));
// The delta from the start of the map-compare instruction to the
- // test eax instruction. We use masm_ directly here instead of the
+ // test instruction. We use masm_ directly here instead of the
// double underscore macro because the macro sometimes uses macro
// expansion to turn into something that can't return a value. This
// is encountered when doing generated code coverage tests.
int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site());
- __ test(value.reg(), Immediate(-delta_to_patch_site));
+ // Here we use masm_-> instead of the double underscore macro because this
+ // is the instruction that gets patched and coverage code gets in the way.
+ masm_->test(value.reg(), Immediate(-delta_to_patch_site));
__ IncrementCounter(&Counters::keyed_load_inline_miss, 1);
// The receiver and key were spilled by the call, so their state as
diff --git a/src/codegen-ia32.h b/src/ia32/codegen-ia32.h
similarity index 100%
rename from src/codegen-ia32.h
rename to src/ia32/codegen-ia32.h
diff --git a/src/cpu-ia32.cc b/src/ia32/cpu-ia32.cc
similarity index 100%
rename from src/cpu-ia32.cc
rename to src/ia32/cpu-ia32.cc
diff --git a/src/debug-ia32.cc b/src/ia32/debug-ia32.cc
similarity index 100%
rename from src/debug-ia32.cc
rename to src/ia32/debug-ia32.cc
diff --git a/src/disasm-ia32.cc b/src/ia32/disasm-ia32.cc
similarity index 100%
rename from src/disasm-ia32.cc
rename to src/ia32/disasm-ia32.cc
diff --git a/src/frames-ia32.cc b/src/ia32/frames-ia32.cc
similarity index 100%
rename from src/frames-ia32.cc
rename to src/ia32/frames-ia32.cc
diff --git a/src/frames-ia32.h b/src/ia32/frames-ia32.h
similarity index 100%
rename from src/frames-ia32.h
rename to src/ia32/frames-ia32.h
diff --git a/src/ic-ia32.cc b/src/ia32/ic-ia32.cc
similarity index 96%
rename from src/ic-ia32.cc
rename to src/ia32/ic-ia32.cc
index 664303f..559ac24 100644
--- a/src/ic-ia32.cc
+++ b/src/ia32/ic-ia32.cc
@@ -123,23 +123,19 @@
}
-// 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);
}
@@ -268,7 +264,7 @@
__ 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);
@@ -493,10 +489,10 @@
__ 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) {
@@ -683,7 +679,7 @@
// 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.
diff --git a/src/jump-target-ia32.cc b/src/ia32/jump-target-ia32.cc
similarity index 100%
rename from src/jump-target-ia32.cc
rename to src/ia32/jump-target-ia32.cc
diff --git a/src/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
similarity index 100%
rename from src/macro-assembler-ia32.cc
rename to src/ia32/macro-assembler-ia32.cc
diff --git a/src/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h
similarity index 100%
rename from src/macro-assembler-ia32.h
rename to src/ia32/macro-assembler-ia32.h
diff --git a/src/regexp-macro-assembler-ia32.cc b/src/ia32/regexp-macro-assembler-ia32.cc
similarity index 99%
rename from src/regexp-macro-assembler-ia32.cc
rename to src/ia32/regexp-macro-assembler-ia32.cc
index 8c92091..83dac54 100644
--- a/src/regexp-macro-assembler-ia32.cc
+++ b/src/ia32/regexp-macro-assembler-ia32.cc
@@ -32,8 +32,8 @@
#include "regexp-stack.h"
#include "macro-assembler.h"
#include "regexp-macro-assembler.h"
-#include "macro-assembler-ia32.h"
-#include "regexp-macro-assembler-ia32.h"
+#include "ia32/macro-assembler-ia32.h"
+#include "ia32/regexp-macro-assembler-ia32.h"
namespace v8 { namespace internal {
diff --git a/src/regexp-macro-assembler-ia32.h b/src/ia32/regexp-macro-assembler-ia32.h
similarity index 100%
rename from src/regexp-macro-assembler-ia32.h
rename to src/ia32/regexp-macro-assembler-ia32.h
diff --git a/src/register-allocator-ia32.cc b/src/ia32/register-allocator-ia32.cc
similarity index 100%
rename from src/register-allocator-ia32.cc
rename to src/ia32/register-allocator-ia32.cc
diff --git a/src/simulator-ia32.cc b/src/ia32/simulator-ia32.cc
similarity index 100%
rename from src/simulator-ia32.cc
rename to src/ia32/simulator-ia32.cc
diff --git a/src/simulator-ia32.h b/src/ia32/simulator-ia32.h
similarity index 100%
rename from src/simulator-ia32.h
rename to src/ia32/simulator-ia32.h
diff --git a/src/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
similarity index 100%
rename from src/stub-cache-ia32.cc
rename to src/ia32/stub-cache-ia32.cc
diff --git a/src/virtual-frame-ia32.cc b/src/ia32/virtual-frame-ia32.cc
similarity index 97%
rename from src/virtual-frame-ia32.cc
rename to src/ia32/virtual-frame-ia32.cc
index 3647ca5..656ef21 100644
--- a/src/virtual-frame-ia32.cc
+++ b/src/ia32/virtual-frame-ia32.cc
@@ -158,6 +158,28 @@
}
+// Clear the dirty bits for the range of elements in
+// [min(stack_pointer_ + 1,begin), end].
+void VirtualFrame::SyncRange(int begin, int end) {
+ ASSERT(begin >= 0);
+ ASSERT(end < elements_.length());
+ // Sync elements below the range if they have not been materialized
+ // on the stack.
+ int start = Min(begin, stack_pointer_ + 1);
+
+ // If positive we have to adjust the stack pointer.
+ int delta = end - stack_pointer_;
+ if (delta > 0) {
+ stack_pointer_ = end;
+ __ sub(Operand(esp), Immediate(delta * kPointerSize));
+ }
+
+ for (int i = start; i <= end; i++) {
+ if (!elements_[i].is_synced()) SyncElementBelowStackPointer(i);
+ }
+}
+
+
void VirtualFrame::MergeTo(VirtualFrame* expected) {
Comment cmnt(masm_, "[ Merge frame");
// We should always be merging the code generator's current frame to an
@@ -467,7 +489,7 @@
// we sync them with the actual frame to allocate space for spilling
// them later. First sync everything above the stack pointer so we can
// use pushes to allocate and initialize the locals.
- SyncRange(stack_pointer_ + 1, elements_.length());
+ SyncRange(stack_pointer_ + 1, elements_.length() - 1);
Handle<Object> undefined = Factory::undefined_value();
FrameElement initial_value =
FrameElement::ConstantElement(undefined, FrameElement::SYNCED);
diff --git a/src/virtual-frame-ia32.h b/src/ia32/virtual-frame-ia32.h
similarity index 100%
rename from src/virtual-frame-ia32.h
rename to src/ia32/virtual-frame-ia32.h
diff --git a/src/json-delay.js b/src/json-delay.js
new file mode 100644
index 0000000..90150c6
--- /dev/null
+++ b/src/json-delay.js
@@ -0,0 +1,254 @@
+// 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 ParseJSONUnfiltered(text) {
+ var s = $String(text);
+ var f = %CompileString("(" + text + ")", -1, true);
+ return f();
+}
+
+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();
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 40241e6..89d11eb 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -43,10 +43,10 @@
#include "regexp-stack.h"
#ifdef ARM
-#include "regexp-macro-assembler-arm.h"
+#include "arm/regexp-macro-assembler-arm.h"
#else // IA32
-#include "macro-assembler-ia32.h"
-#include "regexp-macro-assembler-ia32.h"
+#include "ia32/macro-assembler-ia32.h"
+#include "ia32/regexp-macro-assembler-ia32.h"
#endif
#include "interpreter-irregexp.h"
diff --git a/src/macro-assembler.h b/src/macro-assembler.h
index 84a1eef..d21f479 100644
--- a/src/macro-assembler.h
+++ b/src/macro-assembler.h
@@ -30,20 +30,20 @@
#ifdef ARM
-#include "constants-arm.h"
+#include "arm/constants-arm.h"
#include "assembler.h"
-#include "assembler-arm.h"
-#include "assembler-arm-inl.h"
+#include "arm/assembler-arm.h"
+#include "arm/assembler-arm-inl.h"
#include "code.h" // must be after assembler_*.h
-#include "macro-assembler-arm.h"
+#include "arm/macro-assembler-arm.h"
#else // ia32
#include "assembler.h"
-#include "assembler-ia32.h"
-#include "assembler-ia32-inl.h"
+#include "ia32/assembler-ia32.h"
+#include "ia32/assembler-ia32-inl.h"
#include "code.h" // must be after assembler_*.h
-#include "macro-assembler-ia32.h"
+#include "ia32/macro-assembler-ia32.h"
#endif
diff --git a/src/macros.py b/src/macros.py
index d78ecd9..ebfd816 100644
--- a/src/macros.py
+++ b/src/macros.py
@@ -84,6 +84,8 @@
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);
diff --git a/src/messages.js b/src/messages.js
index fa6fb1f..df8a2d1 100644
--- a/src/messages.js
+++ b/src/messages.js
@@ -114,6 +114,9 @@
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"
};
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index 635ef0f..e172014 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -558,8 +558,6 @@
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();
@@ -579,7 +577,6 @@
VerifyObjectField(kCodeOffset);
VerifyObjectField(kInstanceClassNameOffset);
VerifyObjectField(kExternalReferenceDataOffset);
- VerifyObjectField(kLazyLoadDataOffset);
VerifyObjectField(kScriptOffset);
VerifyObjectField(kDebugInfoOffset);
}
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 73b9c84..ff64d65 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -1811,6 +1811,16 @@
}
+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));
@@ -2075,7 +2085,6 @@
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)
@@ -2141,8 +2150,8 @@
}
-bool JSFunction::IsLoaded() {
- return shared()->lazy_load_data() == Heap::undefined_value();
+bool JSObject::IsLoaded() {
+ return !map()->needs_loading();
}
diff --git a/src/objects.cc b/src/objects.cc
index 31c5bab..55fc971 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -358,7 +358,7 @@
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,
@@ -377,7 +377,7 @@
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);
@@ -389,7 +389,7 @@
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);
@@ -1158,7 +1158,7 @@
(index - map()->inobject_properties()) < properties()->length() ||
map()->unused_property_fields() == 0);
// Allocate a new map for the object.
- Object* r = map()->Copy();
+ Object* r = map()->CopyDropDescriptors();
if (r->IsFailure()) return r;
Map* new_map = Map::cast(r);
if (allow_map_transition) {
@@ -1203,7 +1203,7 @@
if (new_descriptors->IsFailure()) return new_descriptors;
// Allocate a new map for the object.
- Object* new_map = map()->Copy();
+ Object* new_map = map()->CopyDropDescriptors();
if (new_map->IsFailure()) return new_map;
DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
@@ -1361,7 +1361,7 @@
DescriptorArray::cast(descriptors_unchecked);
// Make a new map for the object.
- Object* new_map_unchecked = map()->Copy();
+ Object* new_map_unchecked = map()->CopyDropDescriptors();
if (new_map_unchecked->IsFailure()) return new_map_unchecked;
Map* new_map = Map::cast(new_map_unchecked);
new_map->set_instance_descriptors(new_descriptors);
@@ -2032,7 +2032,7 @@
dictionary->SetNextEnumerationIndex(index);
// Allocate new map.
- obj = map()->Copy();
+ obj = map()->CopyDropDescriptors();
if (obj->IsFailure()) return obj;
Map* new_map = Map::cast(obj);
@@ -2704,24 +2704,29 @@
}
-Object* Map::Copy() {
+Object* Map::CopyDropDescriptors() {
Object* result = Heap::AllocateMap(instance_type(), instance_size());
if (result->IsFailure()) return result;
Map::cast(result)->set_prototype(prototype());
Map::cast(result)->set_constructor(constructor());
// Don't copy descriptors, so map transitions always remain a forest.
+ // If we retained the same descriptors we would have two maps
+ // pointing to the same transition which is bad because the garbage
+ // collector relies on being able to reverse pointers from transitions
+ // to maps. If properties need to be retained use CopyDropTransitions.
Map::cast(result)->set_instance_descriptors(Heap::empty_descriptor_array());
// Please note instance_type and instance_size are set when allocated.
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;
}
Object* Map::CopyDropTransitions() {
- Object* new_map = Copy();
+ Object* new_map = CopyDropDescriptors();
if (new_map->IsFailure()) return new_map;
Object* descriptors = instance_descriptors()->RemoveTransitions();
if (descriptors->IsFailure()) return descriptors;
@@ -7153,7 +7158,7 @@
descriptors->Sort();
// Allocate new map.
- Object* new_map = obj->map()->Copy();
+ Object* new_map = obj->map()->CopyDropDescriptors();
if (new_map->IsFailure()) return new_map;
// Transform the object.
diff --git a/src/objects.h b/src/objects.h
index db3c449..8e76591 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -1242,6 +1242,9 @@
String* name,
PropertyAttributes* attributes);
+ // Tells whether this object needs to be loaded.
+ inline bool IsLoaded();
+
bool HasProperty(String* name) {
return GetPropertyAttribute(name) != ABSENT;
}
@@ -2397,6 +2400,10 @@
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
@@ -2447,6 +2454,20 @@
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));
@@ -2474,7 +2495,7 @@
DECL_ACCESSORS(code_cache, FixedArray)
// Returns a copy of the map.
- Object* Copy();
+ Object* CopyDropDescriptors();
// Returns a copy of the map, with all transitions dropped from the
// instance descriptors.
@@ -2550,7 +2571,7 @@
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.
@@ -2561,6 +2582,10 @@
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);
};
@@ -2677,10 +2702,6 @@
// 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)
@@ -2754,9 +2775,7 @@
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;
@@ -2809,9 +2828,6 @@
// 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
diff --git a/src/property.h b/src/property.h
index 65d4a0d..60a9b54 100644
--- a/src/property.h
+++ b/src/property.h
@@ -245,14 +245,25 @@
// 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);
diff --git a/src/runtime.cc b/src/runtime.cc
index 2b350a5..a1e23b4 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -4824,14 +4824,18 @@
static Object* Runtime_CompileString(Arguments args) {
HandleScope scope;
- ASSERT(args.length() == 2);
+ ASSERT_EQ(3, args.length());
CONVERT_ARG_CHECKED(String, source, 0);
CONVERT_ARG_CHECKED(Smi, line_offset, 1);
+ CONVERT_ARG_CHECKED(Oddball, is_json, 2)
// Compile source string in the global context.
Handle<Context> context(Top::context()->global_context());
- Handle<JSFunction> boilerplate =
- Compiler::CompileEval(source, context, line_offset->value(), true);
+ Handle<JSFunction> boilerplate = Compiler::CompileEval(source,
+ context,
+ line_offset->value(),
+ true,
+ is_json->IsTrue());
if (boilerplate.is_null()) return Failure::Exception();
Handle<JSFunction> fun =
Factory::NewFunctionFromBoilerplate(boilerplate, context);
@@ -4856,7 +4860,7 @@
// Compile source string in the current context.
Handle<JSFunction> boilerplate =
- Compiler::CompileEval(source, context, 0, is_global);
+ Compiler::CompileEval(source, context, 0, is_global, false);
if (boilerplate.is_null()) return Failure::Exception();
Handle<JSFunction> fun =
Factory::NewFunctionFromBoilerplate(boilerplate, context);
@@ -6479,7 +6483,8 @@
Compiler::CompileEval(function_source,
context,
0,
- context->IsGlobalContext());
+ context->IsGlobalContext(),
+ false);
if (boilerplate.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function =
Factory::NewFunctionFromBoilerplate(boilerplate, context);
@@ -6537,7 +6542,11 @@
// Compile the source to be evaluated.
Handle<JSFunction> boilerplate =
- Handle<JSFunction>(Compiler::CompileEval(source, context, 0, true));
+ Handle<JSFunction>(Compiler::CompileEval(source,
+ context,
+ 0,
+ true,
+ false));
if (boilerplate.is_null()) return Failure::Exception();
Handle<JSFunction> compiled_function =
Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
diff --git a/src/runtime.h b/src/runtime.h
index 6bd19f6..b29ce70 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -194,7 +194,7 @@
F(NumberIsFinite, 1) \
\
/* Globals */ \
- F(CompileString, 2) \
+ F(CompileString, 3) \
F(GlobalPrint, 1) \
\
/* Eval */ \
diff --git a/src/string.js b/src/string.js
index 3ccad9a..c7a838e 100644
--- a/src/string.js
+++ b/src/string.js
@@ -812,6 +812,11 @@
}
+function StringToJSON(key) {
+ return CheckJSONPrimitive(this.valueOf());
+}
+
+
// -------------------------------------------------------------------
function SetupString() {
@@ -858,7 +863,8 @@
"small", StringSmall,
"strike", StringStrike,
"sub", StringSub,
- "sup", StringSup
+ "sup", StringSup,
+ "toJSON", StringToJSON
));
}
diff --git a/src/v8.cc b/src/v8.cc
index fbe3d5d..c0124e4 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -113,10 +113,6 @@
Heap::TearDown();
Logger::TearDown();
-#ifdef ENABLE_DEBUGGER_SUPPORT
- Debugger::TearDown();
-#endif
-
has_been_setup_ = false;
has_been_disposed_ = true;
}
diff --git a/src/v8natives.js b/src/v8natives.js
index 9772e2f..29a24b4 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -110,7 +110,7 @@
'be the global object from which eval originated');
}
- var f = %CompileString(x, 0);
+ var f = %CompileString(x, 0, false);
if (!IS_FUNCTION(f)) return f;
return f.call(this);
@@ -121,7 +121,7 @@
function GlobalExecScript(expr, lang) {
// NOTE: We don't care about the character casing.
if (!lang || /javascript/i.test(lang)) {
- var f = %CompileString(ToString(expr), 0);
+ var f = %CompileString(ToString(expr), 0, false);
f.call(%GlobalReceiver(global));
}
return null;
@@ -312,13 +312,19 @@
}
+function BooleanToJSON(key) {
+ return CheckJSONPrimitive(this.valueOf());
+}
+
+
// ----------------------------------------------------------------------------
function SetupBoolean() {
InstallFunctions($Boolean.prototype, DONT_ENUM, $Array(
"toString", BooleanToString,
- "valueOf", BooleanValueOf
+ "valueOf", BooleanValueOf,
+ "toJSON", BooleanToJSON
));
}
@@ -418,6 +424,18 @@
}
+function CheckJSONPrimitive(val) {
+ if (!IsPrimitive(val))
+ throw MakeTypeError('result_not_primitive', ['toJSON', val]);
+ return val;
+}
+
+
+function NumberToJSON(key) {
+ return CheckJSONPrimitive(this.valueOf());
+}
+
+
// ----------------------------------------------------------------------------
function SetupNumber() {
@@ -455,7 +473,8 @@
"valueOf", NumberValueOf,
"toFixed", NumberToFixed,
"toExponential", NumberToExponential,
- "toPrecision", NumberToPrecision
+ "toPrecision", NumberToPrecision,
+ "toJSON", NumberToJSON
));
}
@@ -521,7 +540,7 @@
// The call to SetNewFunctionAttributes will ensure the prototype
// property of the resulting function is enumerable (ECMA262, 15.3.5.2).
- var f = %CompileString(source, -1)();
+ var f = %CompileString(source, -1, false)();
%FunctionSetName(f, "anonymous");
return %SetNewFunctionAttributes(f);
}
diff --git a/src/virtual-frame.cc b/src/virtual-frame.cc
index a03e31a..cef1d80 100644
--- a/src/virtual-frame.cc
+++ b/src/virtual-frame.cc
@@ -213,40 +213,14 @@
}
-// Clear the dirty bits for the range of elements in
-// [min(stack_pointer_ + 1,begin), end).
-void VirtualFrame::SyncRange(int begin, int end) {
- ASSERT(begin >= 0);
- ASSERT(end <= elements_.length());
- if (begin > stack_pointer_) {
- // Elements between stack_pointer_ + 1 and begin must also be synced.
- for (int i = stack_pointer_ + 1; i < end; i++) {
- SyncElementByPushing(i);
- }
- } else if (end <= stack_pointer_ + 1) {
- for (int i = begin; i < end; i++) {
- if (!elements_[i].is_synced()) {
- SyncElementBelowStackPointer(i);
- }
- }
- } else {
- // Split into two ranges that each satisfy a condition above.
- SyncRange(begin, stack_pointer_ + 1);
- SyncRange(stack_pointer_ + 1, end);
- }
-}
-
-
// Clear the dirty bit for the element at a given index.
void VirtualFrame::SyncElementAt(int index) {
if (index <= stack_pointer_) {
- if (!elements_[index].is_synced()) {
- SyncElementBelowStackPointer(index);
- }
+ if (!elements_[index].is_synced()) SyncElementBelowStackPointer(index);
+ } else if (index == stack_pointer_ + 1) {
+ SyncElementByPushing(index);
} else {
- for (int i = stack_pointer_ + 1; i <= index; i++) {
- SyncElementByPushing(i);
- }
+ SyncRange(stack_pointer_ + 1, index);
}
}
@@ -310,7 +284,7 @@
ASSERT(height() >= spilled_args);
ASSERT(dropped_args <= spilled_args);
- SyncRange(0, elements_.length());
+ SyncRange(0, elements_.length() - 1);
// Spill registers.
for (int i = 0; i < kNumRegisters; i++) {
if (is_used(i)) {
diff --git a/src/virtual-frame.h b/src/virtual-frame.h
index 99b4f76..13e68b0 100644
--- a/src/virtual-frame.h
+++ b/src/virtual-frame.h
@@ -198,9 +198,9 @@
} } // namespace v8::internal
#ifdef ARM
-#include "virtual-frame-arm.h"
+#include "arm/virtual-frame-arm.h"
#else // ia32
-#include "virtual-frame-ia32.h"
+#include "ia32/virtual-frame-ia32.h"
#endif
#endif // V8_VIRTUAL_FRAME_H_