Version 3.9.18
Ensure consistency of Math.sqrt on Intel platforms.
Remove static initializers in v8. (issue 1859)
Add explicit dependency on v8_base in the GYP-based build.
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@11017 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 9ba1362..7e351fd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2012-03-13: Version 3.9.18
+
+ Ensure consistency of Math.sqrt on Intel platforms.
+
+ Remove static initializers in v8. (issue 1859)
+
+ Add explicit dependency on v8_base in the GYP-based build.
+
+ Performance and stability improvements on all platforms.
+
+
2012-03-12: Version 3.9.17
Fixed VFP detection through compiler defines. (issue 1996)
diff --git a/src/SConscript b/src/SConscript
index fde7a80..0d0b535 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -101,6 +101,7 @@
objects.cc
objects-printer.cc
objects-visiting.cc
+ once.cc
parser.cc
preparser.cc
preparse-data.cc
diff --git a/src/api.cc b/src/api.cc
index d8c7ba0..27d4086 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1430,7 +1430,7 @@
ScriptData* ScriptData::PreCompile(const char* input, int length) {
- i::Utf8ToUC16CharacterStream stream(
+ i::Utf8ToUtf16CharacterStream stream(
reinterpret_cast<const unsigned char*>(input), length);
return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping);
}
@@ -1439,11 +1439,11 @@
ScriptData* ScriptData::PreCompile(v8::Handle<String> source) {
i::Handle<i::String> str = Utils::OpenHandle(*source);
if (str->IsExternalTwoByteString()) {
- i::ExternalTwoByteStringUC16CharacterStream stream(
+ i::ExternalTwoByteStringUtf16CharacterStream stream(
i::Handle<i::ExternalTwoByteString>::cast(str), 0, str->length());
return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping);
} else {
- i::GenericStringUC16CharacterStream stream(str, 0, str->length());
+ i::GenericStringUtf16CharacterStream stream(str, 0, str->length());
return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_scoping);
}
}
@@ -3690,7 +3690,7 @@
int String::Utf8Length() const {
i::Handle<i::String> str = Utils::OpenHandle(this);
if (IsDeadCheck(str->GetIsolate(), "v8::String::Utf8Length()")) return 0;
- return str->Utf8Length();
+ return i::Utf8Length(str);
}
@@ -3736,11 +3736,13 @@
int i;
int pos = 0;
int nchars = 0;
+ int previous = unibrow::Utf16::kNoPreviousCharacter;
for (i = 0; i < len && (capacity == -1 || pos < fast_end); i++) {
i::uc32 c = write_input_buffer.GetNext();
- int written = unibrow::Utf8::Encode(buffer + pos, c);
+ int written = unibrow::Utf8::Encode(buffer + pos, c, previous);
pos += written;
nchars++;
+ previous = c;
}
if (i < len) {
// For the last characters we need to check the length for each one
@@ -3749,16 +3751,33 @@
char intermediate[unibrow::Utf8::kMaxEncodedSize];
for (; i < len && pos < capacity; i++) {
i::uc32 c = write_input_buffer.GetNext();
- int written = unibrow::Utf8::Encode(intermediate, c);
- if (pos + written <= capacity) {
- for (int j = 0; j < written; j++)
- buffer[pos + j] = intermediate[j];
+ if (unibrow::Utf16::IsTrailSurrogate(c) &&
+ unibrow::Utf16::IsLeadSurrogate(previous)) {
+ // We can't use the intermediate buffer here because the encoding
+ // of surrogate pairs is done under assumption that you can step
+ // back and fix the UTF8 stream. Luckily we only need space for one
+ // more byte, so there is always space.
+ ASSERT(pos < capacity);
+ int written = unibrow::Utf8::Encode(buffer + pos, c, previous);
+ ASSERT(written == 1);
pos += written;
nchars++;
} else {
- // We've reached the end of the buffer
- break;
+ int written =
+ unibrow::Utf8::Encode(intermediate,
+ c,
+ unibrow::Utf16::kNoPreviousCharacter);
+ if (pos + written <= capacity) {
+ for (int j = 0; j < written; j++)
+ buffer[pos + j] = intermediate[j];
+ pos += written;
+ nchars++;
+ } else {
+ // We've reached the end of the buffer
+ break;
+ }
}
+ previous = c;
}
}
if (nchars_ref != NULL) *nchars_ref = nchars;
@@ -4014,7 +4033,7 @@
bool v8::V8::Initialize() {
- i::Isolate* isolate = i::Isolate::UncheckedCurrent();
+ i::Isolate* isolate = i::Isolate::Current();
if (isolate != NULL && isolate->IsInitialized()) {
return true;
}
@@ -4907,7 +4926,7 @@
Local<Integer> v8::Integer::New(int32_t value) {
- i::Isolate* isolate = i::Isolate::UncheckedCurrent();
+ i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate, "v8::Integer::New()");
if (i::Smi::IsValid(value)) {
return Utils::IntegerToLocal(i::Handle<i::Object>(i::Smi::FromInt(value),
@@ -5185,7 +5204,7 @@
Isolate* Isolate::GetCurrent() {
- i::Isolate* isolate = i::Isolate::UncheckedCurrent();
+ i::Isolate* isolate = i::Isolate::Current();
return reinterpret_cast<Isolate*>(isolate);
}
@@ -5240,7 +5259,8 @@
TryCatch try_catch;
Handle<String> str = obj->ToString();
if (str.IsEmpty()) return;
- length_ = str->Utf8Length();
+ i::Handle<i::String> i_str = Utils::OpenHandle(*str);
+ length_ = i::Utf8Length(i_str);
str_ = i::NewArray<char>(length_ + 1);
str->WriteUtf8(str_);
}
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index ff15221..85be7d6 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -238,20 +238,21 @@
// add(sp, sp, 4) instruction (aka Pop())
const Instr kPopInstruction =
- al | PostIndex | 4 | LeaveCC | I | sp.code() * B16 | sp.code() * B12;
+ al | PostIndex | 4 | LeaveCC | I | kRegister_sp_Code * B16 |
+ kRegister_sp_Code * B12;
// str(r, MemOperand(sp, 4, NegPreIndex), al) instruction (aka push(r))
// register r is not encoded.
const Instr kPushRegPattern =
- al | B26 | 4 | NegPreIndex | sp.code() * B16;
+ al | B26 | 4 | NegPreIndex | kRegister_sp_Code * B16;
// ldr(r, MemOperand(sp, 4, PostIndex), al) instruction (aka pop(r))
// register r is not encoded.
const Instr kPopRegPattern =
- al | B26 | L | 4 | PostIndex | sp.code() * B16;
+ al | B26 | L | 4 | PostIndex | kRegister_sp_Code * B16;
// mov lr, pc
-const Instr kMovLrPc = al | MOV | pc.code() | lr.code() * B12;
+const Instr kMovLrPc = al | MOV | kRegister_pc_Code | kRegister_lr_Code * B12;
// ldr rd, [pc, #offset]
const Instr kLdrPCMask = kCondMask | 15 * B24 | 7 * B20 | 15 * B16;
-const Instr kLdrPCPattern = al | 5 * B24 | L | pc.code() * B16;
+const Instr kLdrPCPattern = al | 5 * B24 | L | kRegister_pc_Code * B16;
// blxcc rm
const Instr kBlxRegMask =
15 * B24 | 15 * B20 | 15 * B16 | 15 * B12 | 15 * B8 | 15 * B4;
@@ -273,13 +274,13 @@
// A mask for the Rd register for push, pop, ldr, str instructions.
const Instr kLdrRegFpOffsetPattern =
- al | B26 | L | Offset | fp.code() * B16;
+ al | B26 | L | Offset | kRegister_fp_Code * B16;
const Instr kStrRegFpOffsetPattern =
- al | B26 | Offset | fp.code() * B16;
+ al | B26 | Offset | kRegister_fp_Code * B16;
const Instr kLdrRegFpNegOffsetPattern =
- al | B26 | L | NegOffset | fp.code() * B16;
+ al | B26 | L | NegOffset | kRegister_fp_Code * B16;
const Instr kStrRegFpNegOffsetPattern =
- al | B26 | NegOffset | fp.code() * B16;
+ al | B26 | NegOffset | kRegister_fp_Code * B16;
const Instr kLdrStrInstrTypeMask = 0xffff0000;
const Instr kLdrStrInstrArgumentMask = 0x0000ffff;
const Instr kLdrStrOffsetMask = 0x00000fff;
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index 11e39df..e1fa3cf 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -124,24 +124,47 @@
int code_;
};
-const Register no_reg = { -1 };
+// These constants are used in several locations, including static initializers
+const int kRegister_no_reg_Code = -1;
+const int kRegister_r0_Code = 0;
+const int kRegister_r1_Code = 1;
+const int kRegister_r2_Code = 2;
+const int kRegister_r3_Code = 3;
+const int kRegister_r4_Code = 4;
+const int kRegister_r5_Code = 5;
+const int kRegister_r6_Code = 6;
+const int kRegister_r7_Code = 7;
+const int kRegister_r8_Code = 8;
+const int kRegister_r9_Code = 9;
+const int kRegister_r10_Code = 10;
+const int kRegister_fp_Code = 11;
+const int kRegister_ip_Code = 12;
+const int kRegister_sp_Code = 13;
+const int kRegister_lr_Code = 14;
+const int kRegister_pc_Code = 15;
-const Register r0 = { 0 };
-const Register r1 = { 1 };
-const Register r2 = { 2 };
-const Register r3 = { 3 };
-const Register r4 = { 4 };
-const Register r5 = { 5 };
-const Register r6 = { 6 };
-const Register r7 = { 7 };
-const Register r8 = { 8 }; // Used as context register.
-const Register r9 = { 9 }; // Used as lithium codegen scratch register.
-const Register r10 = { 10 }; // Used as roots register.
-const Register fp = { 11 };
-const Register ip = { 12 };
-const Register sp = { 13 };
-const Register lr = { 14 };
-const Register pc = { 15 };
+const Register no_reg = { kRegister_no_reg_Code };
+
+const Register r0 = { kRegister_r0_Code };
+const Register r1 = { kRegister_r1_Code };
+const Register r2 = { kRegister_r2_Code };
+const Register r3 = { kRegister_r3_Code };
+const Register r4 = { kRegister_r4_Code };
+const Register r5 = { kRegister_r5_Code };
+const Register r6 = { kRegister_r6_Code };
+const Register r7 = { kRegister_r7_Code };
+// Used as context register.
+const Register r8 = { kRegister_r8_Code };
+// Used as lithium codegen scratch register.
+const Register r9 = { kRegister_r9_Code };
+// Used as roots register.
+const Register r10 = { kRegister_r10_Code };
+const Register fp = { kRegister_fp_Code };
+const Register ip = { kRegister_ip_Code };
+const Register sp = { kRegister_sp_Code };
+const Register lr = { kRegister_lr_Code };
+const Register pc = { kRegister_pc_Code };
+
// Single word VFP register.
struct SwVfpRegister {
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 250f020..f772db9 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -480,7 +480,7 @@
__ b(gt, ¬_special);
// For 1 or -1 we need to or in the 0 exponent (biased to 1023).
- static const uint32_t exponent_word_for_1 =
+ const uint32_t exponent_word_for_1 =
HeapNumber::kExponentBias << HeapNumber::kExponentShift;
__ orr(exponent, exponent, Operand(exponent_word_for_1), LeaveCC, eq);
// 1, 0 and -1 all have 0 for the second word.
@@ -4237,7 +4237,7 @@
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
// The displacement is the offset of the last parameter (if any)
// relative to the frame pointer.
- static const int kDisplacement =
+ const int kDisplacement =
StandardFrameConstants::kCallerSPOffset - kPointerSize;
// Check that the key is a smi.
@@ -4622,10 +4622,10 @@
// sp[8]: subject string
// sp[12]: JSRegExp object
- static const int kLastMatchInfoOffset = 0 * kPointerSize;
- static const int kPreviousIndexOffset = 1 * kPointerSize;
- static const int kSubjectOffset = 2 * kPointerSize;
- static const int kJSRegExpOffset = 3 * kPointerSize;
+ const int kLastMatchInfoOffset = 0 * kPointerSize;
+ const int kPreviousIndexOffset = 1 * kPointerSize;
+ const int kSubjectOffset = 2 * kPointerSize;
+ const int kJSRegExpOffset = 3 * kPointerSize;
Label runtime, invoke_regexp;
@@ -4824,8 +4824,8 @@
__ IncrementCounter(isolate->counters()->regexp_entry_native(), 1, r0, r2);
// Isolates: note we add an additional parameter here (isolate pointer).
- static const int kRegExpExecuteArguments = 8;
- static const int kParameterRegisters = 4;
+ const int kRegExpExecuteArguments = 8;
+ const int kParameterRegisters = 4;
__ EnterExitFrame(false, kRegExpExecuteArguments - kParameterRegisters);
// Stack pointer now points to cell where return address is to be written.
@@ -5714,7 +5714,7 @@
// scratch: -
// Perform a number of probes in the symbol table.
- static const int kProbes = 4;
+ const int kProbes = 4;
Label found_in_symbol_table;
Label next_probe[kProbes];
Register candidate = scratch5; // Scratch register contains candidate.
@@ -5839,9 +5839,9 @@
// 0 <= from <= to <= string.length.
// If any of these assumptions fail, we call the runtime system.
- static const int kToOffset = 0 * kPointerSize;
- static const int kFromOffset = 1 * kPointerSize;
- static const int kStringOffset = 2 * kPointerSize;
+ const int kToOffset = 0 * kPointerSize;
+ const int kFromOffset = 1 * kPointerSize;
+ const int kStringOffset = 2 * kPointerSize;
__ Ldrd(r2, r3, MemOperand(sp, kToOffset));
STATIC_ASSERT(kFromOffset == kToOffset + 4);
@@ -7085,43 +7085,45 @@
RememberedSetAction action;
};
+#define REG(Name) { kRegister_ ## Name ## _Code }
-struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
+static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
// Used in RegExpExecStub.
- { r6, r4, r7, EMIT_REMEMBERED_SET },
- { r6, r2, r7, EMIT_REMEMBERED_SET },
+ { REG(r6), REG(r4), REG(r7), EMIT_REMEMBERED_SET },
+ { REG(r6), REG(r2), REG(r7), EMIT_REMEMBERED_SET },
// Used in CompileArrayPushCall.
// Also used in StoreIC::GenerateNormal via GenerateDictionaryStore.
// Also used in KeyedStoreIC::GenerateGeneric.
- { r3, r4, r5, EMIT_REMEMBERED_SET },
+ { REG(r3), REG(r4), REG(r5), EMIT_REMEMBERED_SET },
// Used in CompileStoreGlobal.
- { r4, r1, r2, OMIT_REMEMBERED_SET },
+ { REG(r4), REG(r1), REG(r2), OMIT_REMEMBERED_SET },
// Used in StoreStubCompiler::CompileStoreField via GenerateStoreField.
- { r1, r2, r3, EMIT_REMEMBERED_SET },
- { r3, r2, r1, EMIT_REMEMBERED_SET },
+ { REG(r1), REG(r2), REG(r3), EMIT_REMEMBERED_SET },
+ { REG(r3), REG(r2), REG(r1), EMIT_REMEMBERED_SET },
// Used in KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField.
- { r2, r1, r3, EMIT_REMEMBERED_SET },
- { r3, r1, r2, EMIT_REMEMBERED_SET },
+ { REG(r2), REG(r1), REG(r3), EMIT_REMEMBERED_SET },
+ { REG(r3), REG(r1), REG(r2), EMIT_REMEMBERED_SET },
// KeyedStoreStubCompiler::GenerateStoreFastElement.
- { r3, r2, r4, EMIT_REMEMBERED_SET },
- { r2, r3, r4, EMIT_REMEMBERED_SET },
+ { REG(r3), REG(r2), REG(r4), EMIT_REMEMBERED_SET },
+ { REG(r2), REG(r3), REG(r4), EMIT_REMEMBERED_SET },
// ElementsTransitionGenerator::GenerateSmiOnlyToObject
// and ElementsTransitionGenerator::GenerateSmiOnlyToDouble
// and ElementsTransitionGenerator::GenerateDoubleToObject
- { r2, r3, r9, EMIT_REMEMBERED_SET },
- { r2, r3, r9, OMIT_REMEMBERED_SET },
+ { REG(r2), REG(r3), REG(r9), EMIT_REMEMBERED_SET },
+ { REG(r2), REG(r3), REG(r9), OMIT_REMEMBERED_SET },
// ElementsTransitionGenerator::GenerateDoubleToObject
- { r6, r2, r0, EMIT_REMEMBERED_SET },
- { r2, r6, r9, EMIT_REMEMBERED_SET },
+ { REG(r6), REG(r2), REG(r0), EMIT_REMEMBERED_SET },
+ { REG(r2), REG(r6), REG(r9), EMIT_REMEMBERED_SET },
// StoreArrayLiteralElementStub::Generate
- { r5, r0, r6, EMIT_REMEMBERED_SET },
+ { REG(r5), REG(r0), REG(r6), EMIT_REMEMBERED_SET },
// Null termination.
- { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET}
+ { REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET}
};
+#undef REG
bool RecordWriteStub::IsPregenerated() {
- for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
+ for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
!entry->object.is(no_reg);
entry++) {
if (object_.is(entry->object) &&
@@ -7148,7 +7150,7 @@
void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() {
- for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
+ for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
!entry->object.is(no_reg);
entry++) {
RecordWriteStub stub(entry->object,
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 6e18277..befd8f2 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -37,8 +37,7 @@
#define __ ACCESS_MASM(masm)
-TranscendentalFunction CreateTranscendentalFunction(
- TranscendentalCache::Type type) {
+UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) {
switch (type) {
case TranscendentalCache::SIN: return &sin;
case TranscendentalCache::COS: return &cos;
@@ -50,6 +49,10 @@
}
+UnaryMathFunction CreateSqrtFunction() {
+ return &sqrt;
+}
+
// -------------------------------------------------------------------------
// Platform-specific RuntimeCallHelper functions.
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 36421d9..cdc1947 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -1098,6 +1098,14 @@
}
+LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
+ LOperand* receiver = UseRegisterAtStart(instr->receiver());
+ LOperand* function = UseRegisterAtStart(instr->function());
+ LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
+ return AssignEnvironment(DefineSameAsFirst(result));
+}
+
+
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
LOperand* function = UseFixed(instr->function(), r1);
LOperand* receiver = UseFixed(instr->receiver(), r0);
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index ae19677..62cde6e 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -178,7 +178,8 @@
V(ForInCacheArray) \
V(CheckMapValue) \
V(LoadFieldByIndex) \
- V(DateField)
+ V(DateField) \
+ V(WrapReceiver)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
@@ -468,6 +469,20 @@
};
+class LWrapReceiver: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LWrapReceiver(LOperand* receiver, LOperand* function) {
+ inputs_[0] = receiver;
+ inputs_[1] = function;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver")
+
+ LOperand* receiver() { return inputs_[0]; }
+ LOperand* function() { return inputs_[1]; }
+};
+
+
class LApplyArguments: public LTemplateInstruction<1, 4, 0> {
public:
LApplyArguments(LOperand* function,
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 012ea45..66b2c58 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -2800,15 +2800,10 @@
}
-void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
+void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
Register receiver = ToRegister(instr->receiver());
Register function = ToRegister(instr->function());
- Register length = ToRegister(instr->length());
- Register elements = ToRegister(instr->elements());
Register scratch = scratch0();
- ASSERT(receiver.is(r0)); // Used for parameter count.
- ASSERT(function.is(r1)); // Required by InvokeFunction.
- ASSERT(ToRegister(instr->result()).is(r0));
// If the receiver is null or undefined, we have to pass the global
// object as a receiver to normal functions. Values have to be
@@ -2849,6 +2844,18 @@
__ ldr(receiver,
FieldMemOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
__ bind(&receiver_ok);
+}
+
+
+void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
+ Register receiver = ToRegister(instr->receiver());
+ Register function = ToRegister(instr->function());
+ Register length = ToRegister(instr->length());
+ Register elements = ToRegister(instr->elements());
+ Register scratch = scratch0();
+ ASSERT(receiver.is(r0)); // Used for parameter count.
+ ASSERT(function.is(r1)); // Required by InvokeFunction.
+ ASSERT(ToRegister(instr->result()).is(r0));
// Copy the arguments to this function possibly from the
// adaptor frame below it.
diff --git a/src/arm/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc
index de83c13..10ff2dd 100644
--- a/src/arm/regexp-macro-assembler-arm.cc
+++ b/src/arm/regexp-macro-assembler-arm.cc
@@ -472,7 +472,7 @@
uc16 minus,
uc16 mask,
Label* on_not_equal) {
- ASSERT(minus < String::kMaxUC16CharCode);
+ ASSERT(minus < String::kMaxUtf16CodeUnit);
__ sub(r0, current_character(), Operand(minus));
__ and_(r0, r0, Operand(mask));
__ cmp(r0, Operand(c));
diff --git a/src/assembler.cc b/src/assembler.cc
index 07509b5..4944202 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -45,6 +45,7 @@
#include "ic.h"
#include "isolate.h"
#include "jsregexp.h"
+#include "lazy-instance.h"
#include "platform.h"
#include "regexp-macro-assembler.h"
#include "regexp-stack.h"
@@ -84,15 +85,36 @@
namespace v8 {
namespace internal {
+// -----------------------------------------------------------------------------
+// Common double constants.
-const double DoubleConstant::min_int = kMinInt;
-const double DoubleConstant::one_half = 0.5;
-const double DoubleConstant::minus_zero = -0.0;
-const double DoubleConstant::uint8_max_value = 255;
-const double DoubleConstant::zero = 0.0;
-const double DoubleConstant::canonical_non_hole_nan = OS::nan_value();
-const double DoubleConstant::the_hole_nan = BitCast<double>(kHoleNanInt64);
-const double DoubleConstant::negative_infinity = -V8_INFINITY;
+struct DoubleConstant BASE_EMBEDDED {
+ double min_int;
+ double one_half;
+ double minus_zero;
+ double zero;
+ double uint8_max_value;
+ double negative_infinity;
+ double canonical_non_hole_nan;
+ double the_hole_nan;
+};
+
+struct InitializeDoubleConstants {
+ static void Construct(DoubleConstant* double_constants) {
+ double_constants->min_int = kMinInt;
+ double_constants->one_half = 0.5;
+ double_constants->minus_zero = -0.0;
+ double_constants->uint8_max_value = 255;
+ double_constants->zero = 0.0;
+ double_constants->canonical_non_hole_nan = OS::nan_value();
+ double_constants->the_hole_nan = BitCast<double>(kHoleNanInt64);
+ double_constants->negative_infinity = -V8_INFINITY;
+ }
+};
+
+static LazyInstance<DoubleConstant, InitializeDoubleConstants>::type
+ double_constants = LAZY_INSTANCE_INITIALIZER;
+
const char* const RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING";
// -----------------------------------------------------------------------------
@@ -937,49 +959,49 @@
ExternalReference ExternalReference::address_of_min_int() {
return ExternalReference(reinterpret_cast<void*>(
- const_cast<double*>(&DoubleConstant::min_int)));
+ &double_constants.Pointer()->min_int));
}
ExternalReference ExternalReference::address_of_one_half() {
return ExternalReference(reinterpret_cast<void*>(
- const_cast<double*>(&DoubleConstant::one_half)));
+ &double_constants.Pointer()->one_half));
}
ExternalReference ExternalReference::address_of_minus_zero() {
return ExternalReference(reinterpret_cast<void*>(
- const_cast<double*>(&DoubleConstant::minus_zero)));
+ &double_constants.Pointer()->minus_zero));
}
ExternalReference ExternalReference::address_of_zero() {
return ExternalReference(reinterpret_cast<void*>(
- const_cast<double*>(&DoubleConstant::zero)));
+ &double_constants.Pointer()->zero));
}
ExternalReference ExternalReference::address_of_uint8_max_value() {
return ExternalReference(reinterpret_cast<void*>(
- const_cast<double*>(&DoubleConstant::uint8_max_value)));
+ &double_constants.Pointer()->uint8_max_value));
}
ExternalReference ExternalReference::address_of_negative_infinity() {
return ExternalReference(reinterpret_cast<void*>(
- const_cast<double*>(&DoubleConstant::negative_infinity)));
+ &double_constants.Pointer()->negative_infinity));
}
ExternalReference ExternalReference::address_of_canonical_non_hole_nan() {
return ExternalReference(reinterpret_cast<void*>(
- const_cast<double*>(&DoubleConstant::canonical_non_hole_nan)));
+ &double_constants.Pointer()->canonical_non_hole_nan));
}
ExternalReference ExternalReference::address_of_the_hole_nan() {
return ExternalReference(reinterpret_cast<void*>(
- const_cast<double*>(&DoubleConstant::the_hole_nan)));
+ &double_constants.Pointer()->the_hole_nan));
}
diff --git a/src/assembler.h b/src/assembler.h
index 5063879..918a2a6 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -67,21 +67,6 @@
int jit_cookie_;
};
-// -----------------------------------------------------------------------------
-// Common double constants.
-
-class DoubleConstant: public AllStatic {
- public:
- static const double min_int;
- static const double one_half;
- static const double minus_zero;
- static const double zero;
- static const double uint8_max_value;
- static const double negative_infinity;
- static const double canonical_non_hole_nan;
- static const double the_hole_nan;
-};
-
// -----------------------------------------------------------------------------
// Labels represent pc locations; they are typically jump or call targets.
diff --git a/src/builtins.cc b/src/builtins.cc
index ca202f2..1557f8e 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1570,30 +1570,30 @@
BuiltinExtraArguments extra_args;
};
+#define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} }
+
class BuiltinFunctionTable {
public:
- BuiltinFunctionTable() {
- Builtins::InitBuiltinFunctionTable();
+ BuiltinDesc* functions() {
+ CallOnce(&once_, &Builtins::InitBuiltinFunctionTable);
+ return functions_;
}
- static const BuiltinDesc* functions() { return functions_; }
-
- private:
- static BuiltinDesc functions_[Builtins::builtin_count + 1];
+ OnceType once_;
+ BuiltinDesc functions_[Builtins::builtin_count + 1];
friend class Builtins;
};
-BuiltinDesc BuiltinFunctionTable::functions_[Builtins::builtin_count + 1];
-
-static const BuiltinFunctionTable builtin_function_table_init;
+static BuiltinFunctionTable builtin_function_table =
+ BUILTIN_FUNCTION_TABLE_INIT;
// Define array of pointers to generators and C builtin functions.
// We do this in a sort of roundabout way so that we can do the initialization
// within the lexical scope of Builtins:: and within a context where
// Code::Flags names a non-abstract type.
void Builtins::InitBuiltinFunctionTable() {
- BuiltinDesc* functions = BuiltinFunctionTable::functions_;
+ BuiltinDesc* functions = builtin_function_table.functions_;
functions[builtin_count].generator = NULL;
functions[builtin_count].c_code = NULL;
functions[builtin_count].s_name = NULL;
@@ -1637,7 +1637,7 @@
// Create a scope for the handles in the builtins.
HandleScope scope(isolate);
- const BuiltinDesc* functions = BuiltinFunctionTable::functions();
+ const BuiltinDesc* functions = builtin_function_table.functions();
// For now we generate builtin adaptor code into a stack-allocated
// buffer, before copying it into individual code objects. Be careful
diff --git a/src/codegen.h b/src/codegen.h
index 28a3006..50d70f2 100644
--- a/src/codegen.h
+++ b/src/codegen.h
@@ -87,10 +87,10 @@
// Results of the library implementation of transcendental functions may differ
// from the one we use in our generated code. Therefore we use the same
// generated code both in runtime and compiled code.
-typedef double (*TranscendentalFunction)(double x);
+typedef double (*UnaryMathFunction)(double x);
-TranscendentalFunction CreateTranscendentalFunction(
- TranscendentalCache::Type type);
+UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type);
+UnaryMathFunction CreateSqrtFunction();
class ElementsTransitionGenerator : public AllStatic {
diff --git a/src/debug-agent.cc b/src/debug-agent.cc
index c30afa8..511663d 100644
--- a/src/debug-agent.cc
+++ b/src/debug-agent.cc
@@ -372,8 +372,11 @@
// Calculate the message size in UTF-8 encoding.
int utf8_len = 0;
+ int previous = unibrow::Utf16::kNoPreviousCharacter;
for (int i = 0; i < message.length(); i++) {
- utf8_len += unibrow::Utf8::Length(message[i]);
+ uint16_t character = message[i];
+ utf8_len += unibrow::Utf8::Length(character, previous);
+ previous = character;
}
// Send the header.
@@ -388,17 +391,33 @@
// Send message body as UTF-8.
int buffer_position = 0; // Current buffer position.
+ previous = unibrow::Utf16::kNoPreviousCharacter;
for (int i = 0; i < message.length(); i++) {
// Write next UTF-8 encoded character to buffer.
+ uint16_t character = message[i];
buffer_position +=
- unibrow::Utf8::Encode(buffer + buffer_position, message[i]);
+ unibrow::Utf8::Encode(buffer + buffer_position, character, previous);
ASSERT(buffer_position < kBufferSize);
// Send buffer if full or last character is encoded.
- if (kBufferSize - buffer_position < 3 || i == message.length() - 1) {
- conn->Send(buffer, buffer_position);
- buffer_position = 0;
+ if (kBufferSize - buffer_position <
+ unibrow::Utf16::kMaxExtraUtf8BytesForOneUtf16CodeUnit ||
+ i == message.length() - 1) {
+ if (unibrow::Utf16::IsLeadSurrogate(character)) {
+ const int kEncodedSurrogateLength =
+ unibrow::Utf16::kUtf8BytesToCodeASurrogate;
+ ASSERT(buffer_position >= kEncodedSurrogateLength);
+ conn->Send(buffer, buffer_position - kEncodedSurrogateLength);
+ for (int i = 0; i < kEncodedSurrogateLength; i++) {
+ buffer[i] = buffer[buffer_position + i];
+ }
+ buffer_position = kEncodedSurrogateLength;
+ } else {
+ conn->Send(buffer, buffer_position);
+ buffer_position = 0;
+ }
}
+ previous = character;
}
return true;
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index d069a45..d18c1a6 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -847,7 +847,6 @@
case Translation::ARGUMENTS_OBJECT: {
// Use the arguments marker value as a sentinel and fill in the arguments
// object after the deoptimized frame is built.
- ASSERT(frame_index == 0); // Only supported for first frame.
if (FLAG_trace_deopt) {
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
output_[frame_index]->GetTop() + output_offset,
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index ac30b29..713ce0f 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -81,17 +81,41 @@
#ifdef FLAG_MODE_DECLARE
// Structure used to hold a collection of arguments to the JavaScript code.
+#define JSARGUMENTS_INIT {{}}
struct JSArguments {
public:
- JSArguments();
- JSArguments(int argc, const char** argv);
- int argc() const;
- const char** argv();
- const char*& operator[](int idx);
- JSArguments& operator=(JSArguments args);
+ inline int argc() const {
+ return static_cast<int>(storage_[0]);
+ }
+ inline const char** argv() const {
+ return reinterpret_cast<const char**>(storage_[1]);
+ }
+ inline const char*& operator[] (int idx) const {
+ return argv()[idx];
+ }
+ inline JSArguments& operator=(JSArguments args) {
+ set_argc(args.argc());
+ set_argv(args.argv());
+ return *this;
+ }
+ static JSArguments Create(int argc, const char** argv) {
+ JSArguments args;
+ args.set_argc(argc);
+ args.set_argv(argv);
+ return args;
+ }
private:
- int argc_;
- const char** argv_;
+ void set_argc(int argc) {
+ storage_[0] = argc;
+ }
+ void set_argv(const char** argv) {
+ storage_[1] = reinterpret_cast<AtomicWord>(argv);
+ }
+public:
+ // Contains argc and argv. Unfortunately we have to store these two fields
+ // into a single one to avoid making the initialization macro (which would be
+ // "{ 0, NULL }") contain a coma.
+ AtomicWord storage_[2];
};
#endif
@@ -169,6 +193,7 @@
DEFINE_int(stress_runs, 0, "number of stress runs")
DEFINE_bool(optimize_closures, true, "optimize closures")
DEFINE_bool(inline_construct, false, "inline constructor calls")
+DEFINE_bool(inline_arguments, true, "inline functions with arguments object")
DEFINE_int(loop_weight, 1, "loop weight for representation inference")
DEFINE_bool(optimize_for_in, true,
@@ -417,7 +442,7 @@
#endif // ENABLE_DEBUGGER_SUPPORT
DEFINE_string(map_counters, "", "Map counters to a file")
-DEFINE_args(js_arguments, JSArguments(),
+DEFINE_args(js_arguments, JSARGUMENTS_INIT,
"Pass all remaining arguments to the script. Alias for \"--\".")
#if defined(WEBOS__)
diff --git a/src/flags.cc b/src/flags.cc
index 75e66ce..5720cbd 100644
--- a/src/flags.cc
+++ b/src/flags.cc
@@ -411,7 +411,7 @@
for (int k = i; k < *argc; k++) {
js_argv[k - start_pos] = StrDup(argv[k]);
}
- *flag->args_variable() = JSArguments(js_argc, js_argv);
+ *flag->args_variable() = JSArguments::Create(js_argc, js_argv);
i = *argc; // Consume all arguments
break;
}
@@ -534,19 +534,6 @@
}
}
-JSArguments::JSArguments()
- : argc_(0), argv_(NULL) {}
-JSArguments::JSArguments(int argc, const char** argv)
- : argc_(argc), argv_(argv) {}
-int JSArguments::argc() const { return argc_; }
-const char** JSArguments::argv() { return argv_; }
-const char*& JSArguments::operator[](int idx) { return argv_[idx]; }
-JSArguments& JSArguments::operator=(JSArguments args) {
- argc_ = args.argc_;
- argv_ = args.argv_;
- return *this;
-}
-
void FlagList::EnforceFlagImplications() {
#define FLAG_MODE_DEFINE_IMPLICATIONS
diff --git a/src/frames.cc b/src/frames.cc
index be537c9..7780f01 100644
--- a/src/frames.cc
+++ b/src/frames.cc
@@ -31,6 +31,7 @@
#include "deoptimizer.h"
#include "frames-inl.h"
#include "full-codegen.h"
+#include "lazy-instance.h"
#include "mark-compact.h"
#include "safepoint-table.h"
#include "scopeinfo.h"
@@ -1380,12 +1381,12 @@
};
-static const JSCallerSavedCodeData kCallerSavedCodeData;
-
+static LazyInstance<JSCallerSavedCodeData>::type caller_saved_code_data =
+ LAZY_INSTANCE_INITIALIZER;
int JSCallerSavedCode(int n) {
ASSERT(0 <= n && n < kNumJSCallerSaved);
- return kCallerSavedCodeData.reg_code[n];
+ return caller_saved_code_data.Get().reg_code[n];
}
diff --git a/src/gdb-jit.cc b/src/gdb-jit.cc
index 4192222..d3cd447 100644
--- a/src/gdb-jit.cc
+++ b/src/gdb-jit.cc
@@ -33,6 +33,7 @@
#include "compiler.h"
#include "global-handles.h"
#include "messages.h"
+#include "platform.h"
#include "natives.h"
#include "scopeinfo.h"
@@ -2035,7 +2036,7 @@
}
-Mutex* GDBJITInterface::mutex_ = OS::CreateMutex();
+static LazyMutex mutex = LAZY_MUTEX_INITIALIZER;
void GDBJITInterface::AddCode(const char* name,
@@ -2045,7 +2046,7 @@
CompilationInfo* info) {
if (!FLAG_gdbjit) return;
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex.Pointer());
AssertNoAllocation no_gc;
HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true);
@@ -2126,7 +2127,7 @@
void GDBJITInterface::RemoveCode(Code* code) {
if (!FLAG_gdbjit) return;
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex.Pointer());
HashMap::Entry* e = GetEntries()->Lookup(code,
HashForCodeObject(code),
false);
@@ -2146,7 +2147,7 @@
void GDBJITInterface::RegisterDetailedLineInfo(Code* code,
GDBJITLineInfo* line_info) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex.Pointer());
ASSERT(!IsLineInfoTagged(line_info));
HashMap::Entry* e = GetEntries()->Lookup(code, HashForCodeObject(code), true);
ASSERT(e->value == NULL);
diff --git a/src/gdb-jit.h b/src/gdb-jit.h
index 2cf15bc..0eca938 100644
--- a/src/gdb-jit.h
+++ b/src/gdb-jit.h
@@ -132,9 +132,6 @@
static void RemoveCode(Code* code);
static void RegisterDetailedLineInfo(Code* code, GDBJITLineInfo* line_info);
-
- private:
- static Mutex* mutex_;
};
#define GDBJIT(action) GDBJITInterface::action
diff --git a/src/globals.h b/src/globals.h
index e53cc81..25d4ffe 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -267,8 +267,9 @@
// other bits set.
const uint64_t kQuietNaNMask = static_cast<uint64_t>(0xfff) << 51;
-// ASCII/UC16 constants
+// ASCII/UTF-16 constants
// Code-point values in Unicode 4.0 are 21 bits wide.
+// Code units in UTF-16 are 16 bits wide.
typedef uint16_t uc16;
typedef int32_t uc32;
const int kASCIISize = kCharSize;
diff --git a/src/handles.cc b/src/handles.cc
index 1bb258e..416ecbd 100644
--- a/src/handles.cc
+++ b/src/handles.cc
@@ -800,4 +800,162 @@
}
+// This method determines the type of string involved and then gets the UTF8
+// length of the string. It doesn't flatten the string and has log(n) recursion
+// for a string of length n. If the failure flag gets set, then we have to
+// flatten the string and retry. Failures are caused by surrogate pairs in deep
+// cons strings.
+
+// Single surrogate characters that are encountered in the UTF-16 character
+// sequence of the input string get counted as 3 UTF-8 bytes, because that
+// is the way that WriteUtf8 will encode them. Surrogate pairs are counted and
+// encoded as one 4-byte UTF-8 sequence.
+
+// This function conceptually uses recursion on the two halves of cons strings.
+// However, in order to avoid the recursion going too deep it recurses on the
+// second string of the cons, but iterates on the first substring (by manually
+// eliminating it as a tail recursion). This means it counts the UTF-8 length
+// from the end to the start, which makes no difference to the total.
+
+// Surrogate pairs are recognized even if they are split across two sides of a
+// cons, which complicates the implementation somewhat. Therefore, too deep
+// recursion cannot always be avoided. This case is detected, and the failure
+// flag is set, a signal to the caller that the string should be flattened and
+// the operation retried.
+int Utf8LengthHelper(String* input,
+ int from,
+ int to,
+ bool followed_by_surrogate,
+ int max_recursion,
+ bool* failure,
+ bool* starts_with_surrogate) {
+ if (from == to) return 0;
+ int total = 0;
+ bool dummy;
+ while (true) {
+ if (input->IsAsciiRepresentation()) {
+ *starts_with_surrogate = false;
+ return total + to - from;
+ }
+ switch (StringShape(input).representation_tag()) {
+ case kConsStringTag: {
+ ConsString* str = ConsString::cast(input);
+ String* first = str->first();
+ String* second = str->second();
+ int first_length = first->length();
+ if (first_length - from > to - first_length) {
+ if (first_length < to) {
+ // Right hand side is shorter. No need to check the recursion depth
+ // since this can only happen log(n) times.
+ bool right_starts_with_surrogate = false;
+ total += Utf8LengthHelper(second,
+ 0,
+ to - first_length,
+ followed_by_surrogate,
+ max_recursion - 1,
+ failure,
+ &right_starts_with_surrogate);
+ if (*failure) return 0;
+ followed_by_surrogate = right_starts_with_surrogate;
+ input = first;
+ to = first_length;
+ } else {
+ // We only need the left hand side.
+ input = first;
+ }
+ } else {
+ if (first_length > from) {
+ // Left hand side is shorter.
+ if (first->IsAsciiRepresentation()) {
+ total += first_length - from;
+ *starts_with_surrogate = false;
+ starts_with_surrogate = &dummy;
+ input = second;
+ from = 0;
+ to -= first_length;
+ } else if (second->IsAsciiRepresentation()) {
+ followed_by_surrogate = false;
+ total += to - first_length;
+ input = first;
+ to = first_length;
+ } else if (max_recursion > 0) {
+ bool right_starts_with_surrogate = false;
+ // Recursing on the long one. This may fail.
+ total += Utf8LengthHelper(second,
+ 0,
+ to - first_length,
+ followed_by_surrogate,
+ max_recursion - 1,
+ failure,
+ &right_starts_with_surrogate);
+ if (*failure) return 0;
+ input = first;
+ to = first_length;
+ followed_by_surrogate = right_starts_with_surrogate;
+ } else {
+ *failure = true;
+ return 0;
+ }
+ } else {
+ // We only need the right hand side.
+ input = second;
+ from = 0;
+ to -= first_length;
+ }
+ }
+ continue;
+ }
+ case kExternalStringTag:
+ case kSeqStringTag: {
+ Vector<const uc16> vector = input->GetFlatContent().ToUC16Vector();
+ const uc16* p = vector.start();
+ int previous = unibrow::Utf16::kNoPreviousCharacter;
+ for (int i = from; i < to; i++) {
+ uc16 c = p[i];
+ total += unibrow::Utf8::Length(c, previous);
+ previous = c;
+ }
+ if (to - from > 0) {
+ if (unibrow::Utf16::IsLeadSurrogate(previous) &&
+ followed_by_surrogate) {
+ total -= unibrow::Utf8::kBytesSavedByCombiningSurrogates;
+ }
+ if (unibrow::Utf16::IsTrailSurrogate(p[from])) {
+ *starts_with_surrogate = true;
+ }
+ }
+ return total;
+ }
+ case kSlicedStringTag: {
+ SlicedString* str = SlicedString::cast(input);
+ int offset = str->offset();
+ input = str->parent();
+ from += offset;
+ to += offset;
+ continue;
+ }
+ default:
+ break;
+ }
+ UNREACHABLE();
+ return 0;
+ }
+ return 0;
+}
+
+
+int Utf8Length(Handle<String> str) {
+ bool dummy;
+ bool failure;
+ int len;
+ const int kRecursionBudget = 100;
+ do {
+ failure = false;
+ len = Utf8LengthHelper(
+ *str, 0, str->length(), false, kRecursionBudget, &failure, &dummy);
+ if (failure) FlattenString(str);
+ } while (failure);
+ return len;
+}
+
} } // namespace v8::internal
diff --git a/src/handles.h b/src/handles.h
index 4208913..960696b 100644
--- a/src/handles.h
+++ b/src/handles.h
@@ -174,6 +174,8 @@
// string.
Handle<String> FlattenGetString(Handle<String> str);
+int Utf8Length(Handle<String> str);
+
Handle<Object> SetProperty(Handle<Object> object,
Handle<Object> key,
Handle<Object> value,
diff --git a/src/heap.cc b/src/heap.cc
index da98239..6716370 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -60,8 +60,7 @@
namespace v8 {
namespace internal {
-
-static Mutex* gc_initializer_mutex = OS::CreateMutex();
+static LazyMutex gc_initializer_mutex = LAZY_MUTEX_INITIALIZER;
Heap::Heap()
@@ -4186,8 +4185,6 @@
MaybeObject* Heap::AllocateStringFromUtf8Slow(Vector<const char> string,
PretenureFlag pretenure) {
- // V8 only supports characters in the Basic Multilingual Plane.
- const uc32 kMaxSupportedChar = 0xFFFF;
// Count the number of characters in the UTF-8 string and check if
// it is an ASCII string.
Access<UnicodeCache::Utf8Decoder>
@@ -4195,8 +4192,12 @@
decoder->Reset(string.start(), string.length());
int chars = 0;
while (decoder->has_more()) {
- decoder->GetNext();
- chars++;
+ uint32_t r = decoder->GetNext();
+ if (r <= unibrow::Utf16::kMaxNonSurrogateCharCode) {
+ chars++;
+ } else {
+ chars += 2;
+ }
}
Object* result;
@@ -4207,10 +4208,15 @@
// Convert and copy the characters into the new object.
String* string_result = String::cast(result);
decoder->Reset(string.start(), string.length());
- for (int i = 0; i < chars; i++) {
- uc32 r = decoder->GetNext();
- if (r > kMaxSupportedChar) { r = unibrow::Utf8::kBadChar; }
- string_result->Set(i, r);
+ int i = 0;
+ while (i < chars) {
+ uint32_t r = decoder->GetNext();
+ if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
+ string_result->Set(i++, unibrow::Utf16::LeadSurrogate(r));
+ string_result->Set(i++, unibrow::Utf16::TrailSurrogate(r));
+ } else {
+ string_result->Set(i++, r);
+ }
}
return result;
}
@@ -4267,7 +4273,7 @@
uint32_t hash_field) {
ASSERT(chars >= 0);
// Ensure the chars matches the number of characters in the buffer.
- ASSERT(static_cast<unsigned>(chars) == buffer->Length());
+ ASSERT(static_cast<unsigned>(chars) == buffer->Utf16Length());
// Determine whether the string is ASCII.
bool is_ascii = true;
while (buffer->has_more()) {
@@ -4313,8 +4319,15 @@
ASSERT_EQ(size, answer->Size());
// Fill in the characters.
- for (int i = 0; i < chars; i++) {
- answer->Set(i, buffer->GetNext());
+ int i = 0;
+ while (i < chars) {
+ uint32_t character = buffer->GetNext();
+ if (character > unibrow::Utf16::kMaxNonSurrogateCharCode) {
+ answer->Set(i++, unibrow::Utf16::LeadSurrogate(character));
+ answer->Set(i++, unibrow::Utf16::TrailSurrogate(character));
+ } else {
+ answer->Set(i++, character);
+ }
}
return answer;
}
@@ -5855,7 +5868,7 @@
if (!ConfigureHeapDefault()) return false;
}
- gc_initializer_mutex->Lock();
+ gc_initializer_mutex.Pointer()->Lock();
static bool initialized_gc = false;
if (!initialized_gc) {
initialized_gc = true;
@@ -5863,7 +5876,7 @@
NewSpaceScavenger::Initialize();
MarkCompactCollector::Initialize();
}
- gc_initializer_mutex->Unlock();
+ gc_initializer_mutex.Pointer()->Unlock();
MarkMapPointersAsEncoded(false);
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index f7391dd..6db297b 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -885,6 +885,15 @@
}
+HValue* HWrapReceiver::Canonicalize() {
+ if (HasNoUses()) return NULL;
+ if (receiver()->type().IsJSObject()) {
+ return receiver();
+ }
+ return this;
+}
+
+
void HTypeof::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 5733e51..53f0de1 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -185,7 +185,8 @@
V(ForInCacheArray) \
V(CheckMapValue) \
V(LoadFieldByIndex) \
- V(DateField)
+ V(DateField) \
+ V(WrapReceiver)
#define GVN_FLAG_LIST(V) \
V(Calls) \
@@ -2503,6 +2504,27 @@
};
+class HWrapReceiver: public HTemplateInstruction<2> {
+ public:
+ HWrapReceiver(HValue* receiver, HValue* function) {
+ set_representation(Representation::Tagged());
+ SetOperandAt(0, receiver);
+ SetOperandAt(1, function);
+ }
+
+ virtual Representation RequiredInputRepresentation(int index) {
+ return Representation::Tagged();
+ }
+
+ HValue* receiver() { return OperandAt(0); }
+ HValue* function() { return OperandAt(1); }
+
+ virtual HValue* Canonicalize();
+
+ DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
+};
+
+
class HApplyArguments: public HTemplateInstruction<4> {
public:
HApplyArguments(HValue* function,
@@ -4284,7 +4306,7 @@
virtual bool DataEquals(HValue* other) { return true; }
virtual Range* InferRange(Zone* zone) {
- return new(zone) Range(0, String::kMaxUC16CharCode);
+ return new(zone) Range(0, String::kMaxUtf16CodeUnit);
}
};
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 11b1157..6a7b609 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -2639,10 +2639,14 @@
if (!scope->arguments()->IsStackAllocated()) {
return Bailout("context-allocated arguments");
}
- HArgumentsObject* object = new(zone()) HArgumentsObject;
- AddInstruction(object);
- graph()->SetArgumentsObject(object);
- environment()->Bind(scope->arguments(), object);
+
+ if (!graph()->HasArgumentsObject()) {
+ HArgumentsObject* object = new(zone()) HArgumentsObject;
+ AddInstruction(object);
+ graph()->SetArgumentsObject(object);
+ }
+ environment()->Bind(scope->arguments(),
+ graph()->GetArgumentsObject());
}
}
@@ -5226,10 +5230,21 @@
return false;
}
- // Don't inline functions that uses the arguments object.
+ // If the function uses the arguments object check that inlining of functions
+ // with arguments object is enabled and the arguments-variable is
+ // stack allocated.
if (function->scope()->arguments() != NULL) {
- TraceInline(target, caller, "target requires special argument handling");
- return false;
+ if (!FLAG_inline_arguments) {
+ TraceInline(target, caller, "target uses arguments object");
+ return false;
+ }
+
+ if (!function->scope()->arguments()->IsStackAllocated()) {
+ TraceInline(target,
+ caller,
+ "target uses non-stackallocated arguments object");
+ return false;
+ }
}
// All declarations must be inlineable.
@@ -5307,6 +5322,17 @@
function,
call_kind,
function_state()->is_construct()));
+ // If the function uses arguments object create and bind one.
+ if (function->scope()->arguments() != NULL) {
+ ASSERT(function->scope()->arguments()->IsStackAllocated());
+ if (!graph()->HasArgumentsObject()) {
+ HArgumentsObject* object = new(zone()) HArgumentsObject;
+ AddInstruction(object);
+ graph()->SetArgumentsObject(object);
+ }
+ environment()->Bind(function->scope()->arguments(),
+ graph()->GetArgumentsObject());
+ }
VisitDeclarations(target_info.scope()->declarations());
VisitStatements(function->body());
if (HasStackOverflow()) {
@@ -5645,13 +5671,6 @@
HValue* arg_two_value = environment()->Lookup(arg_two->var());
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
- // Our implementation of arguments (based on this stack frame or an
- // adapter below it) does not work for inlined functions.
- if (function_state()->outer() != NULL) {
- Bailout("Function.prototype.apply optimization in inlined function");
- return true;
- }
-
// Found pattern f.apply(receiver, arguments).
VisitForValue(prop->obj());
if (HasStackOverflow() || current_block() == NULL) return true;
@@ -5662,13 +5681,55 @@
VisitForValue(args->at(0));
if (HasStackOverflow() || current_block() == NULL) return true;
HValue* receiver = Pop();
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
- HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements));
- HInstruction* result =
- new(zone()) HApplyArguments(function, receiver, length, elements);
- result->set_position(expr->position());
- ast_context()->ReturnInstruction(result, expr->id());
- return true;
+
+ if (function_state()->outer() == NULL) {
+ HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
+ HInstruction* length =
+ AddInstruction(new(zone()) HArgumentsLength(elements));
+ HValue* wrapped_receiver =
+ AddInstruction(new(zone()) HWrapReceiver(receiver, function));
+ HInstruction* result =
+ new(zone()) HApplyArguments(function,
+ wrapped_receiver,
+ length,
+ elements);
+ result->set_position(expr->position());
+ ast_context()->ReturnInstruction(result, expr->id());
+ return true;
+ } else {
+ // We are inside inlined function and we know exactly what is inside
+ // arguments object.
+ HValue* context = environment()->LookupContext();
+
+ HValue* wrapped_receiver =
+ AddInstruction(new(zone()) HWrapReceiver(receiver, function));
+ PushAndAdd(new(zone()) HPushArgument(wrapped_receiver));
+
+ int parameter_count = environment()->parameter_count();
+ for (int i = 1; i < environment()->parameter_count(); i++) {
+ PushAndAdd(new(zone()) HPushArgument(environment()->Lookup(i)));
+ }
+
+ if (environment()->outer()->frame_type() == ARGUMENTS_ADAPTOR) {
+ HEnvironment* adaptor = environment()->outer();
+ parameter_count = adaptor->parameter_count();
+
+ for (int i = environment()->parameter_count();
+ i < adaptor->parameter_count();
+ i++) {
+ PushAndAdd(new(zone()) HPushArgument(adaptor->Lookup(i)));
+ }
+ }
+
+ HInvokeFunction* call = new(zone()) HInvokeFunction(
+ context,
+ function,
+ parameter_count);
+ Drop(parameter_count);
+ call->set_position(expr->position());
+ ast_context()->ReturnInstruction(call, expr->id());
+ return true;
+ }
}
diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h
index e5ae475..5a08a2c 100644
--- a/src/ia32/assembler-ia32.h
+++ b/src/ia32/assembler-ia32.h
@@ -97,16 +97,25 @@
int code_;
};
+const int kRegister_eax_Code = 0;
+const int kRegister_ecx_Code = 1;
+const int kRegister_edx_Code = 2;
+const int kRegister_ebx_Code = 3;
+const int kRegister_esp_Code = 4;
+const int kRegister_ebp_Code = 5;
+const int kRegister_esi_Code = 6;
+const int kRegister_edi_Code = 7;
+const int kRegister_no_reg_Code = -1;
-const Register eax = { 0 };
-const Register ecx = { 1 };
-const Register edx = { 2 };
-const Register ebx = { 3 };
-const Register esp = { 4 };
-const Register ebp = { 5 };
-const Register esi = { 6 };
-const Register edi = { 7 };
-const Register no_reg = { -1 };
+const Register eax = { kRegister_eax_Code };
+const Register ecx = { kRegister_ecx_Code };
+const Register edx = { kRegister_edx_Code };
+const Register ebx = { kRegister_ebx_Code };
+const Register esp = { kRegister_esp_Code };
+const Register ebp = { kRegister_ebp_Code };
+const Register esi = { kRegister_esi_Code };
+const Register edi = { kRegister_edi_Code };
+const Register no_reg = { kRegister_no_reg_Code };
inline const char* Register::AllocationIndexToString(int index) {
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index d3e2a91..4faa6a4 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -7024,44 +7024,47 @@
};
-struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
+#define REG(Name) { kRegister_ ## Name ## _Code }
+
+static const AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
// Used in RegExpExecStub.
- { ebx, eax, edi, EMIT_REMEMBERED_SET },
+ { REG(ebx), REG(eax), REG(edi), EMIT_REMEMBERED_SET },
// Used in CompileArrayPushCall.
- { ebx, ecx, edx, EMIT_REMEMBERED_SET },
- { ebx, edi, edx, OMIT_REMEMBERED_SET },
+ { REG(ebx), REG(ecx), REG(edx), EMIT_REMEMBERED_SET },
+ { REG(ebx), REG(edi), REG(edx), OMIT_REMEMBERED_SET },
// Used in CompileStoreGlobal and CallFunctionStub.
- { ebx, ecx, edx, OMIT_REMEMBERED_SET },
+ { REG(ebx), REG(ecx), REG(edx), OMIT_REMEMBERED_SET },
// Used in StoreStubCompiler::CompileStoreField and
// KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField.
- { edx, ecx, ebx, EMIT_REMEMBERED_SET },
+ { REG(edx), REG(ecx), REG(ebx), EMIT_REMEMBERED_SET },
// GenerateStoreField calls the stub with two different permutations of
// registers. This is the second.
- { ebx, ecx, edx, EMIT_REMEMBERED_SET },
+ { REG(ebx), REG(ecx), REG(edx), EMIT_REMEMBERED_SET },
// StoreIC::GenerateNormal via GenerateDictionaryStore
- { ebx, edi, edx, EMIT_REMEMBERED_SET },
+ { REG(ebx), REG(edi), REG(edx), EMIT_REMEMBERED_SET },
// KeyedStoreIC::GenerateGeneric.
- { ebx, edx, ecx, EMIT_REMEMBERED_SET},
+ { REG(ebx), REG(edx), REG(ecx), EMIT_REMEMBERED_SET},
// KeyedStoreStubCompiler::GenerateStoreFastElement.
- { edi, ebx, ecx, EMIT_REMEMBERED_SET},
- { edx, edi, ebx, EMIT_REMEMBERED_SET},
+ { REG(edi), REG(ebx), REG(ecx), EMIT_REMEMBERED_SET},
+ { REG(edx), REG(edi), REG(ebx), EMIT_REMEMBERED_SET},
// ElementsTransitionGenerator::GenerateSmiOnlyToObject
// and ElementsTransitionGenerator::GenerateSmiOnlyToDouble
// and ElementsTransitionGenerator::GenerateDoubleToObject
- { edx, ebx, edi, EMIT_REMEMBERED_SET},
- { edx, ebx, edi, OMIT_REMEMBERED_SET},
+ { REG(edx), REG(ebx), REG(edi), EMIT_REMEMBERED_SET},
+ { REG(edx), REG(ebx), REG(edi), OMIT_REMEMBERED_SET},
// ElementsTransitionGenerator::GenerateDoubleToObject
- { eax, edx, esi, EMIT_REMEMBERED_SET},
- { edx, eax, edi, EMIT_REMEMBERED_SET},
+ { REG(eax), REG(edx), REG(esi), EMIT_REMEMBERED_SET},
+ { REG(edx), REG(eax), REG(edi), EMIT_REMEMBERED_SET},
// StoreArrayLiteralElementStub::Generate
- { ebx, eax, ecx, EMIT_REMEMBERED_SET},
+ { REG(ebx), REG(eax), REG(ecx), EMIT_REMEMBERED_SET},
// Null termination.
- { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET}
+ { REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET}
};
+#undef REG
bool RecordWriteStub::IsPregenerated() {
- for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
+ for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
!entry->object.is(no_reg);
entry++) {
if (object_.is(entry->object) &&
@@ -7089,7 +7092,7 @@
void RecordWriteStub::GenerateFixedRegStubsAheadOfTime() {
- for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
+ for (const AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
!entry->object.is(no_reg);
entry++) {
RecordWriteStub stub(entry->object,
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index de6901f..ea61910 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -57,8 +57,7 @@
#define __ masm.
-TranscendentalFunction CreateTranscendentalFunction(
- TranscendentalCache::Type type) {
+UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) {
size_t actual_size;
// Allocate buffer in executable space.
byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
@@ -99,7 +98,40 @@
CPU::FlushICache(buffer, actual_size);
OS::ProtectCode(buffer, actual_size);
- return FUNCTION_CAST<TranscendentalFunction>(buffer);
+ return FUNCTION_CAST<UnaryMathFunction>(buffer);
+}
+
+
+UnaryMathFunction CreateSqrtFunction() {
+ size_t actual_size;
+ // Allocate buffer in executable space.
+ byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
+ &actual_size,
+ true));
+ // If SSE2 is not available, we can use libc's implementation to ensure
+ // consistency since code by fullcodegen's calls into runtime in that case.
+ if (buffer == NULL || !CpuFeatures::IsSupported(SSE2)) return &sqrt;
+ MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+ // esp[1 * kPointerSize]: raw double input
+ // esp[0 * kPointerSize]: return address
+ // Move double input into registers.
+ {
+ CpuFeatures::Scope use_sse2(SSE2);
+ __ movdbl(xmm0, Operand(esp, 1 * kPointerSize));
+ __ sqrtsd(xmm0, xmm0);
+ __ movdbl(Operand(esp, 1 * kPointerSize), xmm0);
+ // Load result into floating point register as return value.
+ __ fld_d(Operand(esp, 1 * kPointerSize));
+ __ Ret();
+ }
+
+ CodeDesc desc;
+ masm.GetCode(&desc);
+ ASSERT(desc.reloc_size == 0);
+
+ CPU::FlushICache(buffer, actual_size);
+ OS::ProtectCode(buffer, actual_size);
+ return FUNCTION_CAST<UnaryMathFunction>(buffer);
}
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index a656175..04008ee 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -2625,15 +2625,10 @@
}
-void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
+void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
Register receiver = ToRegister(instr->receiver());
Register function = ToRegister(instr->function());
- Register length = ToRegister(instr->length());
- Register elements = ToRegister(instr->elements());
Register scratch = ToRegister(instr->TempAt(0));
- ASSERT(receiver.is(eax)); // Used for parameter count.
- ASSERT(function.is(edi)); // Required by InvokeFunction.
- ASSERT(ToRegister(instr->result()).is(eax));
// If the receiver is null or undefined, we have to pass the global
// object as a receiver to normal functions. Values have to be
@@ -2675,6 +2670,17 @@
__ mov(receiver,
FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
__ bind(&receiver_ok);
+}
+
+
+void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
+ Register receiver = ToRegister(instr->receiver());
+ Register function = ToRegister(instr->function());
+ Register length = ToRegister(instr->length());
+ Register elements = ToRegister(instr->elements());
+ ASSERT(receiver.is(eax)); // Used for parameter count.
+ ASSERT(function.is(edi)); // Required by InvokeFunction.
+ ASSERT(ToRegister(instr->result()).is(eax));
// Copy the arguments to this function possibly from the
// adaptor frame below it.
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index 223fde2..18e4645 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -1111,17 +1111,25 @@
}
+LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
+ LOperand* receiver = UseRegister(instr->receiver());
+ LOperand* function = UseRegisterAtStart(instr->function());
+ LOperand* temp = TempRegister();
+ LWrapReceiver* result =
+ new(zone()) LWrapReceiver(receiver, function, temp);
+ return AssignEnvironment(DefineSameAsFirst(result));
+}
+
+
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
LOperand* function = UseFixed(instr->function(), edi);
LOperand* receiver = UseFixed(instr->receiver(), eax);
LOperand* length = UseFixed(instr->length(), ebx);
LOperand* elements = UseFixed(instr->elements(), ecx);
- LOperand* temp = FixedTemp(edx);
LApplyArguments* result = new(zone()) LApplyArguments(function,
receiver,
length,
- elements,
- temp);
+ elements);
return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
}
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index dd41bfb..778bd68 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -173,7 +173,8 @@
V(ForInCacheArray) \
V(CheckMapValue) \
V(LoadFieldByIndex) \
- V(DateField)
+ V(DateField) \
+ V(WrapReceiver)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
@@ -456,18 +457,33 @@
};
-class LApplyArguments: public LTemplateInstruction<1, 4, 1> {
+class LWrapReceiver: public LTemplateInstruction<1, 2, 1> {
+ public:
+ LWrapReceiver(LOperand* receiver,
+ LOperand* function,
+ LOperand* temp) {
+ inputs_[0] = receiver;
+ inputs_[1] = function;
+ temps_[0] = temp;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver")
+
+ LOperand* receiver() { return inputs_[0]; }
+ LOperand* function() { return inputs_[1]; }
+};
+
+
+class LApplyArguments: public LTemplateInstruction<1, 4, 0> {
public:
LApplyArguments(LOperand* function,
LOperand* receiver,
LOperand* length,
- LOperand* elements,
- LOperand* temp) {
+ LOperand* elements) {
inputs_[0] = function;
inputs_[1] = receiver;
inputs_[2] = length;
inputs_[3] = elements;
- temps_[0] = temp;
}
DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments")
diff --git a/src/ia32/regexp-macro-assembler-ia32.cc b/src/ia32/regexp-macro-assembler-ia32.cc
index 2c9b60c..04d6b62 100644
--- a/src/ia32/regexp-macro-assembler-ia32.cc
+++ b/src/ia32/regexp-macro-assembler-ia32.cc
@@ -523,7 +523,7 @@
uc16 minus,
uc16 mask,
Label* on_not_equal) {
- ASSERT(minus < String::kMaxUC16CharCode);
+ ASSERT(minus < String::kMaxUtf16CodeUnit);
__ lea(eax, Operand(current_character(), -minus));
__ and_(eax, mask);
__ cmp(eax, c);
diff --git a/src/incremental-marking.cc b/src/incremental-marking.cc
index d034617..c4f166b 100644
--- a/src/incremental-marking.cc
+++ b/src/incremental-marking.cc
@@ -396,7 +396,7 @@
return !FLAG_expose_gc &&
FLAG_incremental_marking &&
!Serializer::enabled() &&
- heap_->PromotedSpaceSize() > kActivationThreshold;
+ heap_->PromotedSpaceSizeOfObjects() > kActivationThreshold;
}
diff --git a/src/isolate.cc b/src/isolate.cc
index 3dfcbb5..625cc56 100644
--- a/src/isolate.cc
+++ b/src/isolate.cc
@@ -38,9 +38,11 @@
#include "heap-profiler.h"
#include "hydrogen.h"
#include "isolate.h"
+#include "lazy-instance.h"
#include "lithium-allocator.h"
#include "log.h"
#include "messages.h"
+#include "platform.h"
#include "regexp-stack.h"
#include "runtime-profiler.h"
#include "scopeinfo.h"
@@ -55,6 +57,31 @@
namespace v8 {
namespace internal {
+struct GlobalState {
+ Thread::LocalStorageKey per_isolate_thread_data_key;
+ Thread::LocalStorageKey isolate_key;
+ Thread::LocalStorageKey thread_id_key;
+ Isolate* default_isolate;
+ Isolate::ThreadDataTable* thread_data_table;
+ Mutex* mutex;
+};
+
+struct InitializeGlobalState {
+ static void Construct(GlobalState* state) {
+ state->isolate_key = Thread::CreateThreadLocalKey();
+ state->thread_id_key = Thread::CreateThreadLocalKey();
+ state->per_isolate_thread_data_key = Thread::CreateThreadLocalKey();
+ state->thread_data_table = new Isolate::ThreadDataTable();
+ state->default_isolate = new Isolate();
+ state->mutex = OS::CreateMutex();
+ // Can't use SetIsolateThreadLocals(default_isolate_, NULL) here
+ // because a non-null thread data may be already set.
+ Thread::SetThreadLocal(state->isolate_key, state->default_isolate);
+ }
+};
+
+static LazyInstance<GlobalState, InitializeGlobalState>::type global_state;
+
Atomic32 ThreadId::highest_thread_id_ = 0;
int ThreadId::AllocateThreadId() {
@@ -64,10 +91,11 @@
int ThreadId::GetCurrentThreadId() {
- int thread_id = Thread::GetThreadLocalInt(Isolate::thread_id_key_);
+ const GlobalState& global = global_state.Get();
+ int thread_id = Thread::GetThreadLocalInt(global.thread_id_key);
if (thread_id == 0) {
thread_id = AllocateThreadId();
- Thread::SetThreadLocalInt(Isolate::thread_id_key_, thread_id);
+ Thread::SetThreadLocalInt(global.thread_id_key, thread_id);
}
return thread_id;
}
@@ -311,44 +339,16 @@
storage->LinkTo(&free_list_);
}
-
-Isolate* Isolate::default_isolate_ = NULL;
-Thread::LocalStorageKey Isolate::isolate_key_;
-Thread::LocalStorageKey Isolate::thread_id_key_;
-Thread::LocalStorageKey Isolate::per_isolate_thread_data_key_;
-Mutex* Isolate::process_wide_mutex_ = OS::CreateMutex();
-Isolate::ThreadDataTable* Isolate::thread_data_table_ = NULL;
-
-
-class IsolateInitializer {
- public:
- IsolateInitializer() {
- Isolate::EnsureDefaultIsolate();
- }
-};
-
-static IsolateInitializer* EnsureDefaultIsolateAllocated() {
- // TODO(isolates): Use the system threading API to do this once?
- static IsolateInitializer static_initializer;
- return &static_initializer;
-}
-
-// This variable only needed to trigger static intialization.
-static IsolateInitializer* static_initializer = EnsureDefaultIsolateAllocated();
-
-
-
-
-
Isolate::PerIsolateThreadData* Isolate::AllocatePerIsolateThreadData(
ThreadId thread_id) {
ASSERT(!thread_id.Equals(ThreadId::Invalid()));
PerIsolateThreadData* per_thread = new PerIsolateThreadData(this, thread_id);
{
- ScopedLock lock(process_wide_mutex_);
- ASSERT(thread_data_table_->Lookup(this, thread_id) == NULL);
- thread_data_table_->Insert(per_thread);
- ASSERT(thread_data_table_->Lookup(this, thread_id) == per_thread);
+ GlobalState* const global = global_state.Pointer();
+ ScopedLock lock(global->mutex);
+ ASSERT(global->thread_data_table->Lookup(this, thread_id) == NULL);
+ global->thread_data_table->Insert(per_thread);
+ ASSERT(global->thread_data_table->Lookup(this, thread_id) == per_thread);
}
return per_thread;
}
@@ -359,8 +359,9 @@
ThreadId thread_id = ThreadId::Current();
PerIsolateThreadData* per_thread = NULL;
{
- ScopedLock lock(process_wide_mutex_);
- per_thread = thread_data_table_->Lookup(this, thread_id);
+ GlobalState* const global = global_state.Pointer();
+ ScopedLock lock(global->mutex);
+ per_thread = global->thread_data_table->Lookup(this, thread_id);
if (per_thread == NULL) {
per_thread = AllocatePerIsolateThreadData(thread_id);
}
@@ -373,26 +374,25 @@
ThreadId thread_id = ThreadId::Current();
PerIsolateThreadData* per_thread = NULL;
{
- ScopedLock lock(process_wide_mutex_);
- per_thread = thread_data_table_->Lookup(this, thread_id);
+ GlobalState* const global = global_state.Pointer();
+ ScopedLock lock(global->mutex);
+ per_thread = global->thread_data_table->Lookup(this, thread_id);
}
return per_thread;
}
+bool Isolate::IsDefaultIsolate() const {
+ return this == global_state.Get().default_isolate;
+}
+
+
void Isolate::EnsureDefaultIsolate() {
- ScopedLock lock(process_wide_mutex_);
- if (default_isolate_ == NULL) {
- isolate_key_ = Thread::CreateThreadLocalKey();
- thread_id_key_ = Thread::CreateThreadLocalKey();
- per_isolate_thread_data_key_ = Thread::CreateThreadLocalKey();
- thread_data_table_ = new Isolate::ThreadDataTable();
- default_isolate_ = new Isolate();
- }
+ GlobalState* const global = global_state.Pointer();
// Can't use SetIsolateThreadLocals(default_isolate_, NULL) here
- // becase a non-null thread data may be already set.
- if (Thread::GetThreadLocal(isolate_key_) == NULL) {
- Thread::SetThreadLocal(isolate_key_, default_isolate_);
+ // because a non-null thread data may be already set.
+ if (Thread::GetThreadLocal(global->isolate_key) == NULL) {
+ Thread::SetThreadLocal(global->isolate_key, global->default_isolate);
}
}
@@ -400,32 +400,48 @@
#ifdef ENABLE_DEBUGGER_SUPPORT
Debugger* Isolate::GetDefaultIsolateDebugger() {
EnsureDefaultIsolate();
- return default_isolate_->debugger();
+ return global_state.Pointer()->default_isolate->debugger();
}
#endif
StackGuard* Isolate::GetDefaultIsolateStackGuard() {
EnsureDefaultIsolate();
- return default_isolate_->stack_guard();
+ return global_state.Pointer()->default_isolate->stack_guard();
+}
+
+
+Thread::LocalStorageKey Isolate::isolate_key() {
+ return global_state.Get().isolate_key;
+}
+
+
+Thread::LocalStorageKey Isolate::thread_id_key() {
+ return global_state.Get().thread_id_key;
+}
+
+
+Thread::LocalStorageKey Isolate::per_isolate_thread_data_key() {
+ return global_state.Get().per_isolate_thread_data_key;
}
void Isolate::EnterDefaultIsolate() {
EnsureDefaultIsolate();
- ASSERT(default_isolate_ != NULL);
+ Isolate* const default_isolate = global_state.Pointer()->default_isolate;
+ ASSERT(default_isolate != NULL);
PerIsolateThreadData* data = CurrentPerIsolateThreadData();
// If not yet in default isolate - enter it.
- if (data == NULL || data->isolate() != default_isolate_) {
- default_isolate_->Enter();
+ if (data == NULL || data->isolate() != default_isolate) {
+ default_isolate->Enter();
}
}
Isolate* Isolate::GetDefaultIsolateForLocking() {
EnsureDefaultIsolate();
- return default_isolate_;
+ return global_state.Pointer()->default_isolate;
}
@@ -1548,8 +1564,8 @@
Deinit();
- { ScopedLock lock(process_wide_mutex_);
- thread_data_table_->RemoveAllThreads(this);
+ { ScopedLock lock(global_state.Pointer()->mutex);
+ global_state.Pointer()->thread_data_table->RemoveAllThreads(this);
}
if (!IsDefaultIsolate()) {
@@ -1602,8 +1618,9 @@
void Isolate::SetIsolateThreadLocals(Isolate* isolate,
PerIsolateThreadData* data) {
- Thread::SetThreadLocal(isolate_key_, isolate);
- Thread::SetThreadLocal(per_isolate_thread_data_key_, data);
+ const GlobalState& global = global_state.Get();
+ Thread::SetThreadLocal(global.isolate_key, isolate);
+ Thread::SetThreadLocal(global.per_isolate_thread_data_key, data);
}
diff --git a/src/isolate.h b/src/isolate.h
index 2c2618a..ea94b8d 100644
--- a/src/isolate.h
+++ b/src/isolate.h
@@ -430,19 +430,25 @@
// not currently set).
static PerIsolateThreadData* CurrentPerIsolateThreadData() {
return reinterpret_cast<PerIsolateThreadData*>(
- Thread::GetThreadLocal(per_isolate_thread_data_key_));
+ Thread::GetThreadLocal(per_isolate_thread_data_key()));
}
// Returns the isolate inside which the current thread is running.
INLINE(static Isolate* Current()) {
+ const Thread::LocalStorageKey key = isolate_key();
Isolate* isolate = reinterpret_cast<Isolate*>(
- Thread::GetExistingThreadLocal(isolate_key_));
+ Thread::GetExistingThreadLocal(key));
+ if (!isolate) {
+ EnsureDefaultIsolate();
+ isolate = reinterpret_cast<Isolate*>(
+ Thread::GetExistingThreadLocal(key));
+ }
ASSERT(isolate != NULL);
return isolate;
}
INLINE(static Isolate* UncheckedCurrent()) {
- return reinterpret_cast<Isolate*>(Thread::GetThreadLocal(isolate_key_));
+ return reinterpret_cast<Isolate*>(Thread::GetThreadLocal(isolate_key()));
}
// Usually called by Init(), but can be called early e.g. to allow
@@ -464,7 +470,7 @@
// for legacy API reasons.
void TearDown();
- bool IsDefaultIsolate() const { return this == default_isolate_; }
+ bool IsDefaultIsolate() const;
// Ensures that process-wide resources and the default isolate have been
// allocated. It is only necessary to call this method in rare cases, for
@@ -489,14 +495,12 @@
// Returns the key used to store the pointer to the current isolate.
// Used internally for V8 threads that do not execute JavaScript but still
// are part of the domain of an isolate (like the context switcher).
- static Thread::LocalStorageKey isolate_key() {
- return isolate_key_;
- }
+ static Thread::LocalStorageKey isolate_key();
// Returns the key used to store process-wide thread IDs.
- static Thread::LocalStorageKey thread_id_key() {
- return thread_id_key_;
- }
+ static Thread::LocalStorageKey thread_id_key();
+
+ static Thread::LocalStorageKey per_isolate_thread_data_key();
// If a client attempts to create a Locker without specifying an isolate,
// we assume that the client is using legacy behavior. Set up the current
@@ -1032,6 +1036,9 @@
private:
Isolate();
+ friend struct GlobalState;
+ friend struct InitializeGlobalState;
+
// The per-process lock should be acquired before the ThreadDataTable is
// modified.
class ThreadDataTable {
@@ -1074,16 +1081,6 @@
DISALLOW_COPY_AND_ASSIGN(EntryStackItem);
};
- // This mutex protects highest_thread_id_, thread_data_table_ and
- // default_isolate_.
- static Mutex* process_wide_mutex_;
-
- static Thread::LocalStorageKey per_isolate_thread_data_key_;
- static Thread::LocalStorageKey isolate_key_;
- static Thread::LocalStorageKey thread_id_key_;
- static Isolate* default_isolate_;
- static ThreadDataTable* thread_data_table_;
-
void Deinit();
static void SetIsolateThreadLocals(Isolate* isolate,
@@ -1105,7 +1102,7 @@
// If one does not yet exist, allocate a new one.
PerIsolateThreadData* FindOrAllocatePerThreadDataForThisThread();
-// PreInits and returns a default isolate. Needed when a new thread tries
+ // PreInits and returns a default isolate. Needed when a new thread tries
// to create a Locker for the first time (the lock itself is in the isolate).
static Isolate* GetDefaultIsolateForLocking();
diff --git a/src/jsregexp.cc b/src/jsregexp.cc
index 7e695bb..8ccbae4 100644
--- a/src/jsregexp.cc
+++ b/src/jsregexp.cc
@@ -1444,7 +1444,7 @@
if (ascii) {
char_mask = String::kMaxAsciiCharCode;
} else {
- char_mask = String::kMaxUC16CharCode;
+ char_mask = String::kMaxUtf16CodeUnit;
}
uc16 exor = c1 ^ c2;
// Check whether exor has only one bit set.
@@ -1546,7 +1546,7 @@
if (ascii) {
max_char = String::kMaxAsciiCharCode;
} else {
- max_char = String::kMaxUC16CharCode;
+ max_char = String::kMaxUtf16CodeUnit;
}
Label success;
@@ -1642,7 +1642,7 @@
macro_assembler->CheckCharacterLT(from, on_failure);
}
}
- if (to != String::kMaxUC16CharCode) {
+ if (to != String::kMaxUtf16CodeUnit) {
if (cc->is_negated()) {
macro_assembler->CheckCharacterLT(to + 1, on_failure);
} else {
@@ -1835,7 +1835,7 @@
if (asc) {
char_mask = String::kMaxAsciiCharCode;
} else {
- char_mask = String::kMaxUC16CharCode;
+ char_mask = String::kMaxUtf16CodeUnit;
}
mask_ = 0;
value_ = 0;
@@ -1887,7 +1887,7 @@
if (compiler->ascii()) {
char_mask = String::kMaxAsciiCharCode;
} else {
- char_mask = String::kMaxUC16CharCode;
+ char_mask = String::kMaxUtf16CodeUnit;
}
if ((mask & char_mask) == char_mask) need_mask = false;
mask &= char_mask;
@@ -1939,7 +1939,7 @@
if (compiler->ascii()) {
char_mask = String::kMaxAsciiCharCode;
} else {
- char_mask = String::kMaxUC16CharCode;
+ char_mask = String::kMaxUtf16CodeUnit;
}
for (int k = 0; k < elms_->length(); k++) {
TextElement elm = elms_->at(k);
@@ -4079,7 +4079,7 @@
int elmc,
ZoneList<CharacterRange>* ranges) {
ASSERT(elmv[0] != 0x0000);
- ASSERT(elmv[elmc-1] != String::kMaxUC16CharCode);
+ ASSERT(elmv[elmc-1] != String::kMaxUtf16CodeUnit);
uc16 last = 0x0000;
for (int i = 0; i < elmc; i += 2) {
ASSERT(last <= elmv[i] - 1);
@@ -4087,7 +4087,7 @@
ranges->Add(CharacterRange(last, elmv[i] - 1));
last = elmv[i + 1] + 1;
}
- ranges->Add(CharacterRange(last, String::kMaxUC16CharCode));
+ ranges->Add(CharacterRange(last, String::kMaxUtf16CodeUnit));
}
@@ -4633,8 +4633,8 @@
from = range.to();
i++;
}
- if (from < String::kMaxUC16CharCode) {
- negated_ranges->Add(CharacterRange(from + 1, String::kMaxUC16CharCode));
+ if (from < String::kMaxUtf16CodeUnit) {
+ negated_ranges->Add(CharacterRange(from + 1, String::kMaxUtf16CodeUnit));
}
}
@@ -4797,7 +4797,7 @@
entry->AddValue(value);
// Bail out if the last interval ended at 0xFFFF since otherwise
// adding 1 will wrap around to 0.
- if (entry->to() == String::kMaxUC16CharCode)
+ if (entry->to() == String::kMaxUtf16CodeUnit)
break;
ASSERT(entry->to() + 1 > current.from());
current.set_from(entry->to() + 1);
@@ -5117,7 +5117,7 @@
int new_length = length + 1;
if (length > 0) {
if (ranges->at(0).from() == 0) new_length--;
- if (ranges->at(length - 1).to() == String::kMaxUC16CharCode) {
+ if (ranges->at(length - 1).to() == String::kMaxUtf16CodeUnit) {
new_length--;
}
}
@@ -5207,14 +5207,14 @@
if (last < range.from())
AddRange(CharacterRange(last, range.from() - 1));
if (range.to() >= last) {
- if (range.to() == String::kMaxUC16CharCode) {
+ if (range.to() == String::kMaxUtf16CodeUnit) {
return;
} else {
last = range.to() + 1;
}
}
}
- AddRange(CharacterRange(last, String::kMaxUC16CharCode));
+ AddRange(CharacterRange(last, String::kMaxUtf16CodeUnit));
}
diff --git a/src/lazy-instance.h b/src/lazy-instance.h
new file mode 100644
index 0000000..09dfe21
--- /dev/null
+++ b/src/lazy-instance.h
@@ -0,0 +1,216 @@
+// Copyright 2012 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.
+
+// The LazyInstance<Type, Traits> class manages a single instance of Type,
+// which will be lazily created on the first time it's accessed. This class is
+// useful for places you would normally use a function-level static, but you
+// need to have guaranteed thread-safety. The Type constructor will only ever
+// be called once, even if two threads are racing to create the object. Get()
+// and Pointer() will always return the same, completely initialized instance.
+//
+// LazyInstance is completely thread safe, assuming that you create it safely.
+// The class was designed to be POD initialized, so it shouldn't require a
+// static constructor. It really only makes sense to declare a LazyInstance as
+// a global variable using the LAZY_INSTANCE_INITIALIZER initializer.
+//
+// LazyInstance is similar to Singleton, except it does not have the singleton
+// property. You can have multiple LazyInstance's of the same type, and each
+// will manage a unique instance. It also preallocates the space for Type, as
+// to avoid allocating the Type instance on the heap. This may help with the
+// performance of creating the instance, and reducing heap fragmentation. This
+// requires that Type be a complete type so we can determine the size. See
+// notes for advanced users below for more explanations.
+//
+// Example usage:
+// static LazyInstance<MyClass>::type my_instance = LAZY_INSTANCE_INITIALIZER;
+// void SomeMethod() {
+// my_instance.Get().SomeMethod(); // MyClass::SomeMethod()
+//
+// MyClass* ptr = my_instance.Pointer();
+// ptr->DoDoDo(); // MyClass::DoDoDo
+// }
+//
+// Additionally you can override the way your instance is constructed by
+// providing your own trait:
+// Example usage:
+// struct MyCreateTrait {
+// static void Construct(MyClass* allocated_ptr) {
+// new (allocated_ptr) MyClass(/* extra parameters... */);
+// }
+// };
+// static LazyInstance<MyClass, MyCreateTrait>::type my_instance =
+// LAZY_INSTANCE_INITIALIZER;
+//
+// Notes for advanced users:
+// LazyInstance can actually be used in two different ways:
+//
+// - "Static mode" which is the default mode since it is the most efficient
+// (no extra heap allocation). In this mode, the instance is statically
+// allocated (stored in the global data section at compile time).
+// The macro LAZY_STATIC_INSTANCE_INITIALIZER (= LAZY_INSTANCE_INITIALIZER)
+// must be used to initialize static lazy instances.
+//
+// - "Dynamic mode". In this mode, the instance is dynamically allocated and
+// constructed (using new) by default. This mode is useful if you have to
+// deal with some code already allocating the instance for you (e.g.
+// OS::Mutex() which returns a new private OS-dependent subclass of Mutex).
+// The macro LAZY_DYNAMIC_INSTANCE_INITIALIZER must be used to initialize
+// dynamic lazy instances.
+
+#ifndef V8_LAZY_INSTANCE_H_
+#define V8_LAZY_INSTANCE_H_
+
+#include "once.h"
+
+namespace v8 {
+namespace internal {
+
+#define LAZY_STATIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, {} }
+#define LAZY_DYNAMIC_INSTANCE_INITIALIZER { V8_ONCE_INIT, 0 }
+
+// Default to static mode.
+#define LAZY_INSTANCE_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
+
+
+template <typename T>
+struct LeakyInstanceTrait {
+ static void Destroy(T* /* instance */) {}
+};
+
+
+// Traits that define how an instance is allocated and accessed.
+
+template <typename T>
+struct StaticallyAllocatedInstanceTrait {
+ typedef char StorageType[sizeof(T)];
+
+ static T* MutableInstance(StorageType* storage) {
+ return reinterpret_cast<T*>(storage);
+ }
+
+ template <typename ConstructTrait>
+ static void InitStorageUsingTrait(StorageType* storage) {
+ ConstructTrait::Construct(MutableInstance(storage));
+ }
+};
+
+
+template <typename T>
+struct DynamicallyAllocatedInstanceTrait {
+ typedef T* StorageType;
+
+ static T* MutableInstance(StorageType* storage) {
+ return *storage;
+ }
+
+ template <typename CreateTrait>
+ static void InitStorageUsingTrait(StorageType* storage) {
+ *storage = CreateTrait::Create();
+ }
+};
+
+
+template <typename T>
+struct DefaultConstructTrait {
+ // Constructs the provided object which was already allocated.
+ static void Construct(T* allocated_ptr) {
+ new(allocated_ptr) T();
+ }
+};
+
+
+template <typename T>
+struct DefaultCreateTrait {
+ static T* Create() {
+ return new T();
+ }
+};
+
+
+// TODO(pliard): Handle instances destruction (using global destructors).
+template <typename T, typename AllocationTrait, typename CreateTrait,
+ typename DestroyTrait /* not used yet. */ >
+struct LazyInstanceImpl {
+ public:
+ typedef typename AllocationTrait::StorageType StorageType;
+
+ private:
+ static void InitInstance(StorageType* storage) {
+ AllocationTrait::template InitStorageUsingTrait<CreateTrait>(storage);
+ }
+
+ void Init() const {
+ CallOnce(&once_, &InitInstance, &storage_);
+ }
+
+ public:
+ T* Pointer() {
+ Init();
+ return AllocationTrait::MutableInstance(&storage_);
+ }
+
+ const T& Get() const {
+ Init();
+ return *AllocationTrait::MutableInstance(&storage_);
+ }
+
+ mutable OnceType once_;
+ // Note that the previous field, OnceType, is an AtomicWord which guarantees
+ // the correct alignment of the storage field below.
+ mutable StorageType storage_;
+};
+
+
+template <typename T,
+ typename CreateTrait = DefaultConstructTrait<T>,
+ typename DestroyTrait = LeakyInstanceTrait<T> >
+struct LazyStaticInstance {
+ typedef LazyInstanceImpl<T, StaticallyAllocatedInstanceTrait<T>, CreateTrait,
+ DestroyTrait> type;
+};
+
+
+template <typename T,
+ typename CreateTrait = DefaultConstructTrait<T>,
+ typename DestroyTrait = LeakyInstanceTrait<T> >
+struct LazyInstance {
+ // A LazyInstance is a LazyStaticInstance.
+ typedef typename LazyStaticInstance<T, CreateTrait, DestroyTrait>::type type;
+};
+
+
+template <typename T,
+ typename CreateTrait = DefaultConstructTrait<T>,
+ typename DestroyTrait = LeakyInstanceTrait<T> >
+struct LazyDynamicInstance {
+ typedef LazyInstanceImpl<T, DynamicallyAllocatedInstanceTrait<T>, CreateTrait,
+ DestroyTrait> type;
+};
+
+} } // namespace v8::internal
+
+#endif // V8_LAZY_INSTANCE_H_
diff --git a/src/lithium-allocator.cc b/src/lithium-allocator.cc
index 83805dc..4396c73 100644
--- a/src/lithium-allocator.cc
+++ b/src/lithium-allocator.cc
@@ -46,29 +46,6 @@
namespace v8 {
namespace internal {
-
-#define DEFINE_OPERAND_CACHE(name, type) \
- name name::cache[name::kNumCachedOperands]; \
- void name::SetUpCache() { \
- for (int i = 0; i < kNumCachedOperands; i++) { \
- cache[i].ConvertTo(type, i); \
- } \
- } \
- static bool name##_initialize() { \
- name::SetUpCache(); \
- return true; \
- } \
- static bool name##_cache_initialized = name##_initialize();
-
-DEFINE_OPERAND_CACHE(LConstantOperand, CONSTANT_OPERAND)
-DEFINE_OPERAND_CACHE(LStackSlot, STACK_SLOT)
-DEFINE_OPERAND_CACHE(LDoubleStackSlot, DOUBLE_STACK_SLOT)
-DEFINE_OPERAND_CACHE(LRegister, REGISTER)
-DEFINE_OPERAND_CACHE(LDoubleRegister, DOUBLE_REGISTER)
-
-#undef DEFINE_OPERAND_CACHE
-
-
static inline LifetimePosition Min(LifetimePosition a, LifetimePosition b) {
return a.Value() < b.Value() ? a : b;
}
diff --git a/src/lithium.cc b/src/lithium.cc
index 5a44fce..aefd8b6 100644
--- a/src/lithium.cc
+++ b/src/lithium.cc
@@ -94,6 +94,31 @@
}
}
+#define DEFINE_OPERAND_CACHE(name, type) \
+ name* name::cache = NULL; \
+ void name::SetUpCache() { \
+ if (cache) return; \
+ cache = new name[kNumCachedOperands]; \
+ for (int i = 0; i < kNumCachedOperands; i++) { \
+ cache[i].ConvertTo(type, i); \
+ } \
+ } \
+
+DEFINE_OPERAND_CACHE(LConstantOperand, CONSTANT_OPERAND)
+DEFINE_OPERAND_CACHE(LStackSlot, STACK_SLOT)
+DEFINE_OPERAND_CACHE(LDoubleStackSlot, DOUBLE_STACK_SLOT)
+DEFINE_OPERAND_CACHE(LRegister, REGISTER)
+DEFINE_OPERAND_CACHE(LDoubleRegister, DOUBLE_REGISTER)
+
+#undef DEFINE_OPERAND_CACHE
+
+void LOperand::SetUpCaches() {
+ LConstantOperand::SetUpCache();
+ LStackSlot::SetUpCache();
+ LDoubleStackSlot::SetUpCache();
+ LRegister::SetUpCache();
+ LDoubleRegister::SetUpCache();
+}
bool LParallelMove::IsRedundant() const {
for (int i = 0; i < move_operands_.length(); ++i) {
diff --git a/src/lithium.h b/src/lithium.h
index ec72695..d1e2e3c 100644
--- a/src/lithium.h
+++ b/src/lithium.h
@@ -69,6 +69,10 @@
ASSERT(this->index() == index);
}
+ // Calls SetUpCache() for each subclass. Don't forget to update this method
+ // if you add a new LOperand subclass.
+ static void SetUpCaches();
+
protected:
static const int kKindFieldWidth = 3;
class KindField : public BitField<Kind, 0, kKindFieldWidth> { };
@@ -264,7 +268,7 @@
private:
static const int kNumCachedOperands = 128;
- static LConstantOperand cache[];
+ static LConstantOperand* cache;
LConstantOperand() : LOperand() { }
explicit LConstantOperand(int index) : LOperand(CONSTANT_OPERAND, index) { }
@@ -299,7 +303,7 @@
private:
static const int kNumCachedOperands = 128;
- static LStackSlot cache[];
+ static LStackSlot* cache;
LStackSlot() : LOperand() { }
explicit LStackSlot(int index) : LOperand(STACK_SLOT, index) { }
@@ -323,7 +327,7 @@
private:
static const int kNumCachedOperands = 128;
- static LDoubleStackSlot cache[];
+ static LDoubleStackSlot* cache;
LDoubleStackSlot() : LOperand() { }
explicit LDoubleStackSlot(int index) : LOperand(DOUBLE_STACK_SLOT, index) { }
@@ -347,7 +351,7 @@
private:
static const int kNumCachedOperands = 16;
- static LRegister cache[];
+ static LRegister* cache;
LRegister() : LOperand() { }
explicit LRegister(int index) : LOperand(REGISTER, index) { }
@@ -371,7 +375,7 @@
private:
static const int kNumCachedOperands = 16;
- static LDoubleRegister cache[];
+ static LDoubleRegister* cache;
LDoubleRegister() : LOperand() { }
explicit LDoubleRegister(int index) : LOperand(DOUBLE_REGISTER, index) { }
diff --git a/src/log.cc b/src/log.cc
index 3979719..21d64df 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -35,6 +35,7 @@
#include "global-handles.h"
#include "log.h"
#include "macro-assembler.h"
+#include "platform.h"
#include "runtime-profiler.h"
#include "serialize.h"
#include "string-stream.h"
@@ -461,18 +462,20 @@
utf8_pos_ += utf8_length;
return;
}
- int uc16_length = Min(str->length(), kUc16BufferSize);
- String::WriteToFlat(str, uc16_buffer_, 0, uc16_length);
+ int uc16_length = Min(str->length(), kUtf16BufferSize);
+ String::WriteToFlat(str, utf16_buffer, 0, uc16_length);
+ int previous = unibrow::Utf16::kNoPreviousCharacter;
for (int i = 0; i < uc16_length && utf8_pos_ < kUtf8BufferSize; ++i) {
- uc16 c = uc16_buffer_[i];
+ uc16 c = utf16_buffer[i];
if (c <= String::kMaxAsciiCharCodeU) {
utf8_buffer_[utf8_pos_++] = static_cast<char>(c);
} else {
- int char_length = unibrow::Utf8::Length(c);
+ int char_length = unibrow::Utf8::Length(c, previous);
if (utf8_pos_ + char_length > kUtf8BufferSize) break;
- unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c);
+ unibrow::Utf8::Encode(utf8_buffer_ + utf8_pos_, c, previous);
utf8_pos_ += char_length;
}
+ previous = c;
}
}
@@ -504,11 +507,11 @@
private:
static const int kUtf8BufferSize = 512;
- static const int kUc16BufferSize = 128;
+ static const int kUtf16BufferSize = 128;
int utf8_pos_;
char utf8_buffer_[kUtf8BufferSize];
- uc16 uc16_buffer_[kUc16BufferSize];
+ uc16 utf16_buffer[kUtf16BufferSize];
};
@@ -1726,13 +1729,14 @@
}
}
+// Protects the state below.
+static LazyMutex active_samplers_mutex = LAZY_MUTEX_INITIALIZER;
-Mutex* SamplerRegistry::mutex_ = OS::CreateMutex();
List<Sampler*>* SamplerRegistry::active_samplers_ = NULL;
bool SamplerRegistry::IterateActiveSamplers(VisitSampler func, void* param) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(active_samplers_mutex.Pointer());
for (int i = 0;
ActiveSamplersExist() && i < active_samplers_->length();
++i) {
@@ -1759,7 +1763,7 @@
void SamplerRegistry::AddActiveSampler(Sampler* sampler) {
ASSERT(sampler->IsActive());
- ScopedLock lock(mutex_);
+ ScopedLock lock(active_samplers_mutex.Pointer());
if (active_samplers_ == NULL) {
active_samplers_ = new List<Sampler*>;
} else {
@@ -1771,7 +1775,7 @@
void SamplerRegistry::RemoveActiveSampler(Sampler* sampler) {
ASSERT(sampler->IsActive());
- ScopedLock lock(mutex_);
+ ScopedLock lock(active_samplers_mutex.Pointer());
ASSERT(active_samplers_ != NULL);
bool removed = active_samplers_->RemoveElement(sampler);
ASSERT(removed);
diff --git a/src/log.h b/src/log.h
index e54f041..1297387 100644
--- a/src/log.h
+++ b/src/log.h
@@ -454,7 +454,6 @@
return active_samplers_ != NULL && !active_samplers_->is_empty();
}
- static Mutex* mutex_; // Protects the state below.
static List<Sampler*>* active_samplers_;
DISALLOW_IMPLICIT_CONSTRUCTORS(SamplerRegistry);
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 94f1091..17be223 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -60,6 +60,8 @@
state_(IDLE),
#endif
sweep_precisely_(false),
+ reduce_memory_footprint_(false),
+ abort_incremental_marking_(false),
compacting_(false),
was_marked_incrementally_(false),
collect_maps_(FLAG_collect_maps),
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 3eaa524..19346af 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -6895,6 +6895,8 @@
ASSERT(state_ == CompareIC::STRINGS);
Label miss;
+ bool equality = Token::IsEqualityOp(op_);
+
// Registers containing left and right operands respectively.
Register left = a1;
Register right = a0;
@@ -6931,32 +6933,43 @@
// Check that both strings are symbols. If they are, we're done
// because we already know they are not identical.
- ASSERT(GetCondition() == eq);
- STATIC_ASSERT(kSymbolTag != 0);
- __ And(tmp3, tmp1, Operand(tmp2));
- __ And(tmp5, tmp3, Operand(kIsSymbolMask));
- Label is_symbol;
- __ Branch(&is_symbol, eq, tmp5, Operand(zero_reg), USE_DELAY_SLOT);
- __ mov(v0, a0); // In the delay slot.
- // Make sure a0 is non-zero. At this point input operands are
- // guaranteed to be non-zero.
- ASSERT(right.is(a0));
- __ Ret();
- __ bind(&is_symbol);
+ if (equality) {
+ ASSERT(GetCondition() == eq);
+ STATIC_ASSERT(kSymbolTag != 0);
+ __ And(tmp3, tmp1, Operand(tmp2));
+ __ And(tmp5, tmp3, Operand(kIsSymbolMask));
+ Label is_symbol;
+ __ Branch(&is_symbol, eq, tmp5, Operand(zero_reg), USE_DELAY_SLOT);
+ __ mov(v0, a0); // In the delay slot.
+ // Make sure a0 is non-zero. At this point input operands are
+ // guaranteed to be non-zero.
+ ASSERT(right.is(a0));
+ __ Ret();
+ __ bind(&is_symbol);
+ }
// Check that both strings are sequential ASCII.
Label runtime;
- __ JumpIfBothInstanceTypesAreNotSequentialAscii(tmp1, tmp2, tmp3, tmp4,
- &runtime);
+ __ JumpIfBothInstanceTypesAreNotSequentialAscii(
+ tmp1, tmp2, tmp3, tmp4, &runtime);
// Compare flat ASCII strings. Returns when done.
- StringCompareStub::GenerateFlatAsciiStringEquals(
- masm, left, right, tmp1, tmp2, tmp3);
+ if (equality) {
+ StringCompareStub::GenerateFlatAsciiStringEquals(
+ masm, left, right, tmp1, tmp2, tmp3);
+ } else {
+ StringCompareStub::GenerateCompareFlatAsciiStrings(
+ masm, left, right, tmp1, tmp2, tmp3, tmp4);
+ }
// Handle more complex cases in runtime.
__ bind(&runtime);
__ Push(left, right);
- __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
+ if (equality) {
+ __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
+ } else {
+ __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+ }
__ bind(&miss);
GenerateMiss(masm);
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index 8cbb771..9acccdc 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -37,8 +37,7 @@
#define __ ACCESS_MASM(masm)
-TranscendentalFunction CreateTranscendentalFunction(
- TranscendentalCache::Type type) {
+UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) {
switch (type) {
case TranscendentalCache::SIN: return &sin;
case TranscendentalCache::COS: return &cos;
@@ -50,6 +49,10 @@
}
+UnaryMathFunction CreateSqrtFunction() {
+ return &sqrt;
+}
+
// -------------------------------------------------------------------------
// Platform-specific RuntimeCallHelper functions.
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index c5ef2cc..b1c8edc 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -2970,6 +2970,52 @@
}
+void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
+ ZoneList<Expression*>* args = expr->arguments();
+ ASSERT(args->length() == 2);
+ ASSERT_NE(NULL, args->at(1)->AsLiteral());
+ Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->handle()));
+
+ VisitForAccumulatorValue(args->at(0)); // Load the object.
+
+ Label runtime, done;
+ Register object = v0;
+ Register result = v0;
+ Register scratch0 = t5;
+ Register scratch1 = a1;
+
+#ifdef DEBUG
+ __ AbortIfSmi(object);
+ __ GetObjectType(object, scratch1, scratch1);
+ __ Assert(eq, "Trying to get date field from non-date.",
+ scratch1, Operand(JS_DATE_TYPE));
+#endif
+
+ if (index->value() == 0) {
+ __ lw(result, FieldMemOperand(object, JSDate::kValueOffset));
+ } else {
+ if (index->value() < JSDate::kFirstUncachedField) {
+ ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
+ __ li(scratch1, Operand(stamp));
+ __ lw(scratch1, MemOperand(scratch1));
+ __ lw(scratch0, FieldMemOperand(object, JSDate::kCacheStampOffset));
+ __ Branch(&runtime, ne, scratch1, Operand(scratch0));
+ __ lw(result, FieldMemOperand(object, JSDate::kValueOffset +
+ kPointerSize * index->value()));
+ __ jmp(&done);
+ }
+ __ bind(&runtime);
+ __ PrepareCallCFunction(2, scratch1);
+ __ li(a1, Operand(index));
+ __ Move(a0, object);
+ __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
+ __ bind(&done);
+ }
+
+ context()->Plug(v0);
+}
+
+
void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
// Load the arguments on the stack and call the runtime function.
ZoneList<Expression*>* args = expr->arguments();
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index d0531ec..607025c 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -1261,6 +1261,46 @@
}
+void LCodeGen::DoDateField(LDateField* instr) {
+ Register object = ToRegister(instr->InputAt(0));
+ Register result = ToRegister(instr->result());
+ Register scratch = ToRegister(instr->TempAt(0));
+ Smi* index = instr->index();
+ Label runtime, done;
+ ASSERT(object.is(a0));
+ ASSERT(result.is(v0));
+ ASSERT(!scratch.is(scratch0()));
+ ASSERT(!scratch.is(object));
+
+#ifdef DEBUG
+ __ AbortIfSmi(object);
+ __ GetObjectType(object, scratch, scratch);
+ __ Assert(eq, "Trying to get date field from non-date.",
+ scratch, Operand(JS_DATE_TYPE));
+#endif
+
+ if (index->value() == 0) {
+ __ lw(result, FieldMemOperand(object, JSDate::kValueOffset));
+ } else {
+ if (index->value() < JSDate::kFirstUncachedField) {
+ ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
+ __ li(scratch, Operand(stamp));
+ __ lw(scratch, MemOperand(scratch));
+ __ lw(scratch0(), FieldMemOperand(object, JSDate::kCacheStampOffset));
+ __ Branch(&runtime, ne, scratch, Operand(scratch0()));
+ __ lw(result, FieldMemOperand(object, JSDate::kValueOffset +
+ kPointerSize * index->value()));
+ __ jmp(&done);
+ }
+ __ bind(&runtime);
+ __ PrepareCallCFunction(2, scratch);
+ __ li(a1, Operand(index));
+ __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
+ __ bind(&done);
+ }
+}
+
+
void LCodeGen::DoBitNotI(LBitNotI* instr) {
Register input = ToRegister(instr->InputAt(0));
Register result = ToRegister(instr->result());
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 1c4e1da..32aae94 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -1604,6 +1604,13 @@
}
+LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
+ LOperand* object = UseFixed(instr->value(), a0);
+ LDateField* result = new LDateField(object, FixedTemp(a1), instr->index());
+ return MarkAsCall(DefineFixed(result, v0), instr);
+}
+
+
LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
LOperand* value = UseRegisterAtStart(instr->index());
LOperand* length = UseRegister(instr->length());
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 2128ce3..7c5a4af 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -177,8 +177,8 @@
V(ForInPrepareMap) \
V(ForInCacheArray) \
V(CheckMapValue) \
- V(LoadFieldByIndex)
-
+ V(LoadFieldByIndex) \
+ V(DateField)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
virtual Opcode opcode() const { return LInstruction::k##type; } \
@@ -989,6 +989,22 @@
};
+class LDateField: public LTemplateInstruction<1, 1, 1> {
+ public:
+ LDateField(LOperand* date, LOperand* temp, Smi* index) : index_(index) {
+ inputs_[0] = date;
+ temps_[0] = temp;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(ValueOf, "date-field")
+ DECLARE_HYDROGEN_ACCESSOR(ValueOf)
+ Smi* index() const { return index_; }
+
+ private:
+ Smi* index_;
+};
+
+
class LThrow: public LTemplateInstruction<0, 1, 0> {
public:
explicit LThrow(LOperand* value) {
diff --git a/src/objects-inl.h b/src/objects-inl.h
index d0e9bf8..ed0c19f 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -4463,7 +4463,11 @@
}
-void StringHasher::AddCharacter(uc32 c) {
+void StringHasher::AddCharacter(uint32_t c) {
+ if (c > unibrow::Utf16::kMaxNonSurrogateCharCode) {
+ AddSurrogatePair(c); // Not inlined.
+ return;
+ }
// Use the Jenkins one-at-a-time hash function to update the hash
// for the given character.
raw_running_hash_ += c;
@@ -4492,8 +4496,12 @@
}
-void StringHasher::AddCharacterNoIndex(uc32 c) {
+void StringHasher::AddCharacterNoIndex(uint32_t c) {
ASSERT(!is_array_index());
+ if (c > unibrow::Utf16::kMaxNonSurrogateCharCode) {
+ AddSurrogatePairNoIndex(c); // Not inlined.
+ return;
+ }
raw_running_hash_ += c;
raw_running_hash_ += (raw_running_hash_ << 10);
raw_running_hash_ ^= (raw_running_hash_ >> 6);
diff --git a/src/objects.cc b/src/objects.cc
index e0a9537..7865ac0 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -6051,9 +6051,11 @@
buffer->Reset(offset, this);
int character_position = offset;
int utf8_bytes = 0;
+ int last = unibrow::Utf16::kNoPreviousCharacter;
while (buffer->has_more() && character_position++ < offset + length) {
uint16_t character = buffer->GetNext();
- utf8_bytes += unibrow::Utf8::Length(character);
+ utf8_bytes += unibrow::Utf8::Length(character, last);
+ last = character;
}
if (length_return) {
@@ -6067,13 +6069,15 @@
buffer->Seek(offset);
character_position = offset;
int utf8_byte_position = 0;
+ last = unibrow::Utf16::kNoPreviousCharacter;
while (buffer->has_more() && character_position++ < offset + length) {
uint16_t character = buffer->GetNext();
if (allow_nulls == DISALLOW_NULLS && character == 0) {
character = ' ';
}
utf8_byte_position +=
- unibrow::Utf8::Encode(result + utf8_byte_position, character);
+ unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
+ last = character;
}
result[utf8_byte_position] = 0;
return SmartArrayPointer<char>(result);
@@ -6387,73 +6391,6 @@
}
-// This method determines the type of string involved and then gets the UTF8
-// length of the string. It doesn't flatten the string and has log(n) recursion
-// for a string of length n.
-int String::Utf8Length(String* input, int from, int to) {
- if (from == to) return 0;
- int total = 0;
- while (true) {
- if (input->IsAsciiRepresentation()) return total + to - from;
- switch (StringShape(input).representation_tag()) {
- case kConsStringTag: {
- ConsString* str = ConsString::cast(input);
- String* first = str->first();
- String* second = str->second();
- int first_length = first->length();
- if (first_length - from < to - first_length) {
- if (first_length > from) {
- // Left hand side is shorter.
- total += Utf8Length(first, from, first_length);
- input = second;
- from = 0;
- to -= first_length;
- } else {
- // We only need the right hand side.
- input = second;
- from -= first_length;
- to -= first_length;
- }
- } else {
- if (first_length <= to) {
- // Right hand side is shorter.
- total += Utf8Length(second, 0, to - first_length);
- input = first;
- to = first_length;
- } else {
- // We only need the left hand side.
- input = first;
- }
- }
- continue;
- }
- case kExternalStringTag:
- case kSeqStringTag: {
- Vector<const uc16> vector = input->GetFlatContent().ToUC16Vector();
- const uc16* p = vector.start();
- for (int i = from; i < to; i++) {
- total += unibrow::Utf8::Length(p[i]);
- }
- return total;
- }
- case kSlicedStringTag: {
- SlicedString* str = SlicedString::cast(input);
- int offset = str->offset();
- input = str->parent();
- from += offset;
- to += offset;
- continue;
- }
- default:
- break;
- }
- UNREACHABLE();
- return 0;
- }
- return 0;
-}
-
-
void Relocatable::PostGarbageCollectionProcessing() {
Isolate* isolate = Isolate::Current();
Relocatable* current = isolate->relocatable_top();
@@ -6847,8 +6784,10 @@
// General slow case check. We know that the ia and ib iterators
// have the same length.
while (ia->has_more()) {
- uc32 ca = ia->GetNext();
- uc32 cb = ib->GetNext();
+ uint32_t ca = ia->GetNext();
+ uint32_t cb = ib->GetNext();
+ ASSERT(ca <= unibrow::Utf16::kMaxNonSurrogateCharCode);
+ ASSERT(cb <= unibrow::Utf16::kMaxNonSurrogateCharCode);
if (ca != cb)
return false;
}
@@ -7031,8 +6970,14 @@
decoder->Reset(str.start(), str.length());
int i;
for (i = 0; i < slen && decoder->has_more(); i++) {
- uc32 r = decoder->GetNext();
- if (Get(i) != r) return false;
+ uint32_t r = decoder->GetNext();
+ if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
+ if (i > slen - 1) return false;
+ if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
+ if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
+ } else {
+ if (Get(i) != r) return false;
+ }
}
return i == slen && !decoder->has_more();
}
@@ -7162,6 +7107,22 @@
}
+void StringHasher::AddSurrogatePair(uc32 c) {
+ uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
+ AddCharacter(lead);
+ uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
+ AddCharacter(trail);
+}
+
+
+void StringHasher::AddSurrogatePairNoIndex(uc32 c) {
+ uint16_t lead = unibrow::Utf16::LeadSurrogate(c);
+ AddCharacterNoIndex(lead);
+ uint16_t trail = unibrow::Utf16::TrailSurrogate(c);
+ AddCharacterNoIndex(trail);
+}
+
+
uint32_t StringHasher::GetHashField() {
ASSERT(is_valid());
if (length_ <= String::kMaxHashCalcLength) {
@@ -10655,7 +10616,7 @@
if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
unibrow::Utf8InputBuffer<> buffer(string_.start(),
static_cast<unsigned>(string_.length()));
- chars_ = buffer.Length();
+ chars_ = buffer.Utf16Length();
hash_field_ = String::ComputeHashField(&buffer, chars_, seed_);
uint32_t result = hash_field_ >> String::kHashShift;
ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
diff --git a/src/objects.h b/src/objects.h
index 7906d14..548dbcf 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -6616,12 +6616,17 @@
inline bool has_trivial_hash();
// Add a character to the hash and update the array index calculation.
- inline void AddCharacter(uc32 c);
+ inline void AddCharacter(uint32_t c);
// Adds a character to the hash but does not update the array index
// calculation. This can only be called when it has been verified
// that the input is not an array index.
- inline void AddCharacterNoIndex(uc32 c);
+ inline void AddCharacterNoIndex(uint32_t c);
+
+ // Add a character above 0xffff as a surrogate pair. These can get into
+ // the hasher through the routines that take a UTF-8 string and make a symbol.
+ void AddSurrogatePair(uc32 c);
+ void AddSurrogatePairNoIndex(uc32 c);
// Returns the value to store in the hash field of a string with
// the given length and contents.
@@ -6871,9 +6876,6 @@
RobustnessFlag robustness_flag = FAST_STRING_TRAVERSAL,
int* length_output = 0);
- inline int Utf8Length() { return Utf8Length(this, 0, length()); }
- static int Utf8Length(String* input, int from, int to);
-
// Return a 16 bit Unicode representation of the string.
// The string should be nearly flat, otherwise the performance of
// of this method may be very bad. Setting robustness_flag to
@@ -6939,7 +6941,7 @@
// Max ASCII char code.
static const int kMaxAsciiCharCode = unibrow::Utf8::kMaxOneByteChar;
static const unsigned kMaxAsciiCharCodeU = unibrow::Utf8::kMaxOneByteChar;
- static const int kMaxUC16CharCode = 0xffff;
+ static const int kMaxUtf16CodeUnit = 0xffff;
// Mask constant for checking if a string has a computed hash code
// and if it is an array index. The least significant bit indicates
diff --git a/src/once.cc b/src/once.cc
new file mode 100644
index 0000000..37fe369
--- /dev/null
+++ b/src/once.cc
@@ -0,0 +1,77 @@
+// Copyright 2012 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.
+
+#include "once.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sched.h>
+#endif
+
+#include "atomicops.h"
+#include "checks.h"
+
+namespace v8 {
+namespace internal {
+
+void CallOnceImpl(OnceType* once, PointerArgFunction init_func, void* arg) {
+ AtomicWord state = Acquire_Load(once);
+ // Fast path. The provided function was already executed.
+ if (state == ONCE_STATE_DONE) {
+ return;
+ }
+
+ // The function execution did not complete yet. The once object can be in one
+ // of the two following states:
+ // - UNINITIALIZED: We are the first thread calling this function.
+ // - EXECUTING_FUNCTION: Another thread is already executing the function.
+ //
+ // First, try to change the state from UNINITIALIZED to EXECUTING_FUNCTION
+ // atomically.
+ state = Acquire_CompareAndSwap(
+ once, ONCE_STATE_UNINITIALIZED, ONCE_STATE_EXECUTING_FUNCTION);
+ if (state == ONCE_STATE_UNINITIALIZED) {
+ // We are the first thread to call this function, so we have to call the
+ // function.
+ init_func(arg);
+ Release_Store(once, ONCE_STATE_DONE);
+ } else {
+ // Another thread has already started executing the function. We need to
+ // wait until it completes the initialization.
+ while (state == ONCE_STATE_EXECUTING_FUNCTION) {
+#ifdef _WIN32
+ ::Sleep(0);
+#else
+ sched_yield();
+#endif
+ state = Acquire_Load(once);
+ }
+ }
+}
+
+} } // namespace v8::internal
diff --git a/src/once.h b/src/once.h
new file mode 100644
index 0000000..a44b8fa
--- /dev/null
+++ b/src/once.h
@@ -0,0 +1,123 @@
+// Copyright 2012 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.
+
+// emulates google3/base/once.h
+//
+// This header is intended to be included only by v8's internal code. Users
+// should not use this directly.
+//
+// This is basically a portable version of pthread_once().
+//
+// This header declares:
+// * A type called OnceType.
+// * A macro V8_DECLARE_ONCE() which declares a (global) variable of type
+// OnceType.
+// * A function CallOnce(OnceType* once, void (*init_func)()).
+// This function, when invoked multiple times given the same OnceType object,
+// will invoke init_func on the first call only, and will make sure none of
+// the calls return before that first call to init_func has finished.
+//
+// Additionally, the following features are supported:
+// * A macro V8_ONCE_INIT which is expanded into the expression used to
+// initialize a OnceType. This is only useful when clients embed a OnceType
+// into a structure of their own and want to initialize it statically.
+// * The user can provide a parameter which CallOnce() forwards to the
+// user-provided function when it is called. Usage example:
+// CallOnce(&my_once, &MyFunctionExpectingIntArgument, 10);
+// * This implementation guarantees that OnceType is a POD (i.e. no static
+// initializer generated).
+//
+// This implements a way to perform lazy initialization. It's more efficient
+// than using mutexes as no lock is needed if initialization has already
+// happened.
+//
+// Example usage:
+// void Init();
+// V8_DECLARE_ONCE(once_init);
+//
+// // Calls Init() exactly once.
+// void InitOnce() {
+// CallOnce(&once_init, &Init);
+// }
+//
+// Note that if CallOnce() is called before main() has begun, it must
+// only be called by the thread that will eventually call main() -- that is,
+// the thread that performs dynamic initialization. In general this is a safe
+// assumption since people don't usually construct threads before main() starts,
+// but it is technically not guaranteed. Unfortunately, Win32 provides no way
+// whatsoever to statically-initialize its synchronization primitives, so our
+// only choice is to assume that dynamic initialization is single-threaded.
+
+#ifndef V8_ONCE_H_
+#define V8_ONCE_H_
+
+#include "atomicops.h"
+
+namespace v8 {
+namespace internal {
+
+typedef AtomicWord OnceType;
+
+#define V8_ONCE_INIT 0
+
+#define V8_DECLARE_ONCE(NAME) ::v8::internal::OnceType NAME
+
+enum {
+ ONCE_STATE_UNINITIALIZED = 0,
+ ONCE_STATE_EXECUTING_FUNCTION = 1,
+ ONCE_STATE_DONE = 2
+};
+
+typedef void (*NoArgFunction)();
+typedef void (*PointerArgFunction)(void* arg);
+
+template <typename T>
+struct OneArgFunction {
+ typedef void (*type)(T);
+};
+
+void CallOnceImpl(OnceType* once, PointerArgFunction init_func, void* arg);
+
+inline void CallOnce(OnceType* once, NoArgFunction init_func) {
+ if (Acquire_Load(once) != ONCE_STATE_DONE) {
+ CallOnceImpl(once, reinterpret_cast<PointerArgFunction>(init_func), NULL);
+ }
+}
+
+
+template <typename Arg>
+inline void CallOnce(OnceType* once,
+ typename OneArgFunction<Arg*>::type init_func, Arg* arg) {
+ if (Acquire_Load(once) != ONCE_STATE_DONE) {
+ CallOnceImpl(once, reinterpret_cast<PointerArgFunction>(init_func),
+ static_cast<void*>(arg));
+ }
+}
+
+} } // namespace v8::internal
+
+#endif // V8_ONCE_H_
diff --git a/src/parser.cc b/src/parser.cc
index ca8cbb9..90dd6a7 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -258,7 +258,7 @@
scanner().literal_ascii_string());
} else {
return isolate()->factory()->LookupTwoByteSymbol(
- scanner().literal_uc16_string());
+ scanner().literal_utf16_string());
}
}
return LookupCachedSymbol(symbol_id);
@@ -279,7 +279,7 @@
scanner().literal_ascii_string());
} else {
result = isolate()->factory()->LookupTwoByteSymbol(
- scanner().literal_uc16_string());
+ scanner().literal_utf16_string());
}
symbol_cache_.at(symbol_id) = result;
return result;
@@ -576,12 +576,12 @@
// Notice that the stream is destroyed at the end of the branch block.
// The last line of the blocks can't be moved outside, even though they're
// identical calls.
- ExternalTwoByteStringUC16CharacterStream stream(
+ ExternalTwoByteStringUtf16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source->length());
scanner_.Initialize(&stream);
return DoParseProgram(info, source, &zone_scope);
} else {
- GenericStringUC16CharacterStream stream(source, 0, source->length());
+ GenericStringUtf16CharacterStream stream(source, 0, source->length());
scanner_.Initialize(&stream);
return DoParseProgram(info, source, &zone_scope);
}
@@ -665,16 +665,16 @@
// Initialize parser state.
source->TryFlatten();
if (source->IsExternalTwoByteString()) {
- ExternalTwoByteStringUC16CharacterStream stream(
+ ExternalTwoByteStringUtf16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source),
shared_info->start_position(),
shared_info->end_position());
FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope);
return result;
} else {
- GenericStringUC16CharacterStream stream(source,
- shared_info->start_position(),
- shared_info->end_position());
+ GenericStringUtf16CharacterStream stream(source,
+ shared_info->start_position(),
+ shared_info->end_position());
FunctionLiteral* result = ParseLazy(info, &stream, &zone_scope);
return result;
}
@@ -682,7 +682,7 @@
FunctionLiteral* Parser::ParseLazy(CompilationInfo* info,
- UC16CharacterStream* source,
+ Utf16CharacterStream* source,
ZoneScope* zone_scope) {
Handle<SharedFunctionInfo> shared_info = info->shared_info();
scanner_.Initialize(source);
@@ -4285,7 +4285,7 @@
// Logs a symbol creation of a literal or identifier.
virtual void LogAsciiSymbol(int start, Vector<const char> literal) { }
- virtual void LogUC16Symbol(int start, Vector<const uc16> literal) { }
+ virtual void LogUtf16Symbol(int start, Vector<const uc16> literal) { }
// Logs an error message and marks the log as containing an error.
// Further logging will be ignored, and ExtractData will return a vector
@@ -5874,7 +5874,7 @@
// Create a Scanner for the preparser to use as input, and preparse the source.
-static ScriptDataImpl* DoPreParse(UC16CharacterStream* source,
+static ScriptDataImpl* DoPreParse(Utf16CharacterStream* source,
int flags,
ParserRecorder* recorder) {
Isolate* isolate = Isolate::Current();
@@ -5915,17 +5915,17 @@
PartialParserRecorder recorder;
int source_length = source->length();
if (source->IsExternalTwoByteString()) {
- ExternalTwoByteStringUC16CharacterStream stream(
+ ExternalTwoByteStringUtf16CharacterStream stream(
Handle<ExternalTwoByteString>::cast(source), 0, source_length);
return DoPreParse(&stream, flags, &recorder);
} else {
- GenericStringUC16CharacterStream stream(source, 0, source_length);
+ GenericStringUtf16CharacterStream stream(source, 0, source_length);
return DoPreParse(&stream, flags, &recorder);
}
}
-ScriptDataImpl* ParserApi::PreParse(UC16CharacterStream* source,
+ScriptDataImpl* ParserApi::PreParse(Utf16CharacterStream* source,
v8::Extension* extension,
int flags) {
Handle<Script> no_script;
diff --git a/src/parser.h b/src/parser.h
index 90ef399..227344f 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -172,7 +172,7 @@
static bool Parse(CompilationInfo* info, int flags);
// Generic preparser generating full preparse data.
- static ScriptDataImpl* PreParse(UC16CharacterStream* source,
+ static ScriptDataImpl* PreParse(Utf16CharacterStream* source,
v8::Extension* extension,
int flags);
@@ -542,7 +542,7 @@
FunctionLiteral* ParseLazy(CompilationInfo* info,
- UC16CharacterStream* source,
+ Utf16CharacterStream* source,
ZoneScope* zone_scope);
Isolate* isolate() { return isolate_; }
@@ -712,7 +712,7 @@
scanner().literal_ascii_string(), tenured);
} else {
return isolate_->factory()->NewStringFromTwoByte(
- scanner().literal_uc16_string(), tenured);
+ scanner().literal_utf16_string(), tenured);
}
}
@@ -722,7 +722,7 @@
scanner().next_literal_ascii_string(), tenured);
} else {
return isolate_->factory()->NewStringFromTwoByte(
- scanner().next_literal_uc16_string(), tenured);
+ scanner().next_literal_utf16_string(), tenured);
}
}
diff --git a/src/platform-cygwin.cc b/src/platform-cygwin.cc
index 2dc1ed8..fa6fce0 100644
--- a/src/platform-cygwin.cc
+++ b/src/platform-cygwin.cc
@@ -628,7 +628,7 @@
interval_(interval) {}
static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::AddActiveSampler(sampler);
if (instance_ == NULL) {
instance_ = new SamplerThread(sampler->interval());
@@ -639,7 +639,7 @@
}
static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::RemoveActiveSampler(sampler);
if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
@@ -725,7 +725,7 @@
RuntimeProfilerRateLimiter rate_limiter_;
// Protects the process wide state below.
- static Mutex* mutex_;
+ static LazyMutex mutex_;
static SamplerThread* instance_;
private:
@@ -733,7 +733,7 @@
};
-Mutex* SamplerThread::mutex_ = OS::CreateMutex();
+LazyMutex SamplerThread::mutex_ = LAZY_MUTEX_INITIALIZER;
SamplerThread* SamplerThread::instance_ = NULL;
diff --git a/src/platform-freebsd.cc b/src/platform-freebsd.cc
index f6a426f..2a9e174 100644
--- a/src/platform-freebsd.cc
+++ b/src/platform-freebsd.cc
@@ -723,7 +723,7 @@
interval_(interval) {}
static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::AddActiveSampler(sampler);
if (instance_ == NULL) {
// Install a signal handler.
@@ -743,7 +743,7 @@
}
static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::RemoveActiveSampler(sampler);
if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
@@ -836,7 +836,7 @@
RuntimeProfilerRateLimiter rate_limiter_;
// Protects the process wide state below.
- static Mutex* mutex_;
+ static LazyMutex mutex_;
static SignalSender* instance_;
static bool signal_handler_installed_;
static struct sigaction old_signal_handler_;
@@ -845,7 +845,7 @@
DISALLOW_COPY_AND_ASSIGN(SignalSender);
};
-Mutex* SignalSender::mutex_ = OS::CreateMutex();
+LazyMutex SignalSender::mutex_ = LAZY_MUTEX_INITIALIZER;
SignalSender* SignalSender::instance_ = NULL;
struct sigaction SignalSender::old_signal_handler_;
bool SignalSender::signal_handler_installed_ = false;
diff --git a/src/platform-linux.cc b/src/platform-linux.cc
index cfcbd91..8be9609 100644
--- a/src/platform-linux.cc
+++ b/src/platform-linux.cc
@@ -1090,7 +1090,7 @@
}
static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::AddActiveSampler(sampler);
if (instance_ == NULL) {
// Start a thread that will send SIGPROF signal to VM threads,
@@ -1103,7 +1103,7 @@
}
static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::RemoveActiveSampler(sampler);
if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
@@ -1206,7 +1206,7 @@
RuntimeProfilerRateLimiter rate_limiter_;
// Protects the process wide state below.
- static Mutex* mutex_;
+ static LazyMutex mutex_;
static SignalSender* instance_;
static bool signal_handler_installed_;
static struct sigaction old_signal_handler_;
@@ -1216,7 +1216,7 @@
};
-Mutex* SignalSender::mutex_ = OS::CreateMutex();
+LazyMutex SignalSender::mutex_ = LAZY_MUTEX_INITIALIZER;
SignalSender* SignalSender::instance_ = NULL;
struct sigaction SignalSender::old_signal_handler_;
bool SignalSender::signal_handler_installed_ = false;
diff --git a/src/platform-macos.cc b/src/platform-macos.cc
index 89abf39..bfcaab0 100644
--- a/src/platform-macos.cc
+++ b/src/platform-macos.cc
@@ -746,7 +746,7 @@
interval_(interval) {}
static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::AddActiveSampler(sampler);
if (instance_ == NULL) {
instance_ = new SamplerThread(sampler->interval());
@@ -757,7 +757,7 @@
}
static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::RemoveActiveSampler(sampler);
if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
@@ -854,7 +854,7 @@
RuntimeProfilerRateLimiter rate_limiter_;
// Protects the process wide state below.
- static Mutex* mutex_;
+ static LazyMutex mutex_;
static SamplerThread* instance_;
private:
@@ -864,7 +864,7 @@
#undef REGISTER_FIELD
-Mutex* SamplerThread::mutex_ = OS::CreateMutex();
+LazyMutex SamplerThread::mutex_ = LAZY_MUTEX_INITIALIZER;
SamplerThread* SamplerThread::instance_ = NULL;
diff --git a/src/platform-openbsd.cc b/src/platform-openbsd.cc
index 0d69971..b79cb71 100644
--- a/src/platform-openbsd.cc
+++ b/src/platform-openbsd.cc
@@ -812,7 +812,7 @@
}
static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::AddActiveSampler(sampler);
if (instance_ == NULL) {
// Start a thread that will send SIGPROF signal to VM threads,
@@ -825,7 +825,7 @@
}
static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::RemoveActiveSampler(sampler);
if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
@@ -919,7 +919,7 @@
RuntimeProfilerRateLimiter rate_limiter_;
// Protects the process wide state below.
- static Mutex* mutex_;
+ static LazyMutex mutex_;
static SignalSender* instance_;
static bool signal_handler_installed_;
static struct sigaction old_signal_handler_;
@@ -929,7 +929,7 @@
};
-Mutex* SignalSender::mutex_ = OS::CreateMutex();
+LazyMutex SignalSender::mutex_ = LAZY_MUTEX_INITIALIZER;
SignalSender* SignalSender::instance_ = NULL;
struct sigaction SignalSender::old_signal_handler_;
bool SignalSender::signal_handler_installed_ = false;
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
index 4543a66..a729b66 100644
--- a/src/platform-posix.cc
+++ b/src/platform-posix.cc
@@ -127,27 +127,25 @@
}
-static Mutex* transcendental_function_mutex = OS::CreateMutex();
-
-#define TRANSCENDENTAL_FUNCTION(name, type) \
-static TranscendentalFunction fast_##name##_function = NULL; \
-double fast_##name(double x) { \
- if (fast_##name##_function == NULL) { \
- ScopedLock lock(transcendental_function_mutex); \
- TranscendentalFunction temp = \
- CreateTranscendentalFunction(type); \
- MemoryBarrier(); \
- fast_##name##_function = temp; \
- } \
- return (*fast_##name##_function)(x); \
+#define UNARY_MATH_FUNCTION(name, generator) \
+static UnaryMathFunction fast_##name##_function = NULL; \
+V8_DECLARE_ONCE(fast_##name##_init_once); \
+void init_fast_##name##_function() { \
+ fast_##name##_function = generator; \
+} \
+double fast_##name(double x) { \
+ CallOnce(&fast_##name##_init_once, \
+ &init_fast_##name##_function); \
+ return (*fast_##name##_function)(x); \
}
-TRANSCENDENTAL_FUNCTION(sin, TranscendentalCache::SIN)
-TRANSCENDENTAL_FUNCTION(cos, TranscendentalCache::COS)
-TRANSCENDENTAL_FUNCTION(tan, TranscendentalCache::TAN)
-TRANSCENDENTAL_FUNCTION(log, TranscendentalCache::LOG)
+UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN))
+UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS))
+UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN))
+UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG))
+UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction())
-#undef TRANSCENDENTAL_FUNCTION
+#undef MATH_FUNCTION
double OS::nan_value() {
@@ -307,14 +305,14 @@
#if defined(V8_TARGET_ARCH_IA32)
static OS::MemCopyFunction memcopy_function = NULL;
-static Mutex* memcopy_function_mutex = OS::CreateMutex();
+static LazyMutex memcopy_function_mutex = LAZY_MUTEX_INITIALIZER;
// Defined in codegen-ia32.cc.
OS::MemCopyFunction CreateMemCopyFunction();
// Copy memory area to disjoint memory area.
void OS::MemCopy(void* dest, const void* src, size_t size) {
if (memcopy_function == NULL) {
- ScopedLock lock(memcopy_function_mutex);
+ ScopedLock lock(memcopy_function_mutex.Pointer());
if (memcopy_function == NULL) {
OS::MemCopyFunction temp = CreateMemCopyFunction();
MemoryBarrier();
diff --git a/src/platform-solaris.cc b/src/platform-solaris.cc
index 004a6ed..50ad353 100644
--- a/src/platform-solaris.cc
+++ b/src/platform-solaris.cc
@@ -733,7 +733,7 @@
}
static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::AddActiveSampler(sampler);
if (instance_ == NULL) {
// Start a thread that will send SIGPROF signal to VM threads,
@@ -746,7 +746,7 @@
}
static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::RemoveActiveSampler(sampler);
if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
@@ -840,7 +840,7 @@
RuntimeProfilerRateLimiter rate_limiter_;
// Protects the process wide state below.
- static Mutex* mutex_;
+ static LazyMutex mutex_;
static SignalSender* instance_;
static bool signal_handler_installed_;
static struct sigaction old_signal_handler_;
@@ -849,7 +849,7 @@
DISALLOW_COPY_AND_ASSIGN(SignalSender);
};
-Mutex* SignalSender::mutex_ = OS::CreateMutex();
+LazyMutex SignalSender::mutex_ = LAZY_MUTEX_INITIALIZER;
SignalSender* SignalSender::instance_ = NULL;
struct sigaction SignalSender::old_signal_handler_;
bool SignalSender::signal_handler_installed_ = false;
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index 53915c6..5600542 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -149,14 +149,14 @@
#if defined(V8_TARGET_ARCH_IA32)
static OS::MemCopyFunction memcopy_function = NULL;
-static Mutex* memcopy_function_mutex = OS::CreateMutex();
+static LazyMutex memcopy_function_mutex = LAZY_MUTEX_INITIALIZER;
// Defined in codegen-ia32.cc.
OS::MemCopyFunction CreateMemCopyFunction();
// Copy memory area to disjoint memory area.
void OS::MemCopy(void* dest, const void* src, size_t size) {
if (memcopy_function == NULL) {
- ScopedLock lock(memcopy_function_mutex);
+ ScopedLock lock(memcopy_function_mutex.Pointer());
if (memcopy_function == NULL) {
OS::MemCopyFunction temp = CreateMemCopyFunction();
MemoryBarrier();
@@ -175,19 +175,16 @@
#ifdef _WIN64
typedef double (*ModuloFunction)(double, double);
static ModuloFunction modulo_function = NULL;
-static Mutex* modulo_function_mutex = OS::CreateMutex();
+V8_DECLARE_ONCE(modulo_function_init_once);
// Defined in codegen-x64.cc.
ModuloFunction CreateModuloFunction();
+void init_modulo_function() {
+ modulo_function = CreateModuloFunction();
+}
+
double modulo(double x, double y) {
- if (modulo_function == NULL) {
- ScopedLock lock(modulo_function_mutex);
- if (modulo_function == NULL) {
- ModuloFunction temp = CreateModuloFunction();
- MemoryBarrier();
- modulo_function = temp;
- }
- }
+ CallOnce(&modulo_function_init_once, &init_modulo_function);
// Note: here we rely on dependent reads being ordered. This is true
// on all architectures we currently support.
return (*modulo_function)(x, y);
@@ -208,27 +205,25 @@
#endif // _WIN64
-static Mutex* transcendental_function_mutex = OS::CreateMutex();
-
-#define TRANSCENDENTAL_FUNCTION(name, type) \
-static TranscendentalFunction fast_##name##_function = NULL; \
-double fast_##name(double x) { \
- if (fast_##name##_function == NULL) { \
- ScopedLock lock(transcendental_function_mutex); \
- TranscendentalFunction temp = \
- CreateTranscendentalFunction(type); \
- MemoryBarrier(); \
- fast_##name##_function = temp; \
- } \
- return (*fast_##name##_function)(x); \
+#define UNARY_MATH_FUNCTION(name, generator) \
+static UnaryMathFunction fast_##name##_function = NULL; \
+V8_DECLARE_ONCE(fast_##name##_init_once); \
+void init_fast_##name##_function() { \
+ fast_##name##_function = generator; \
+} \
+double fast_##name(double x) { \
+ CallOnce(&fast_##name##_init_once, \
+ &init_fast_##name##_function); \
+ return (*fast_##name##_function)(x); \
}
-TRANSCENDENTAL_FUNCTION(sin, TranscendentalCache::SIN)
-TRANSCENDENTAL_FUNCTION(cos, TranscendentalCache::COS)
-TRANSCENDENTAL_FUNCTION(tan, TranscendentalCache::TAN)
-TRANSCENDENTAL_FUNCTION(log, TranscendentalCache::LOG)
+UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN))
+UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS))
+UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN))
+UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG))
+UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction())
-#undef TRANSCENDENTAL_FUNCTION
+#undef MATH_FUNCTION
// ----------------------------------------------------------------------------
@@ -1961,7 +1956,7 @@
interval_(interval) {}
static void AddActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::AddActiveSampler(sampler);
if (instance_ == NULL) {
instance_ = new SamplerThread(sampler->interval());
@@ -1972,7 +1967,7 @@
}
static void RemoveActiveSampler(Sampler* sampler) {
- ScopedLock lock(mutex_);
+ ScopedLock lock(mutex_.Pointer());
SamplerRegistry::RemoveActiveSampler(sampler);
if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
@@ -2058,7 +2053,7 @@
RuntimeProfilerRateLimiter rate_limiter_;
// Protects the process wide state below.
- static Mutex* mutex_;
+ static LazyMutex mutex_;
static SamplerThread* instance_;
private:
@@ -2066,7 +2061,7 @@
};
-Mutex* SamplerThread::mutex_ = OS::CreateMutex();
+LazyMutex SamplerThread::mutex_ = LAZY_MUTEX_INITIALIZER;
SamplerThread* SamplerThread::instance_ = NULL;
diff --git a/src/platform.h b/src/platform.h
index ccb4109..4ec6057 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -79,6 +79,7 @@
#endif // WIN32
#include "atomicops.h"
+#include "lazy-instance.h"
#include "platform-tls.h"
#include "utils.h"
#include "v8globals.h"
@@ -101,6 +102,7 @@
double fast_cos(double input);
double fast_tan(double input);
double fast_log(double input);
+double fast_sqrt(double input);
// Forward declarations.
class Socket;
@@ -528,6 +530,24 @@
virtual bool TryLock() = 0;
};
+struct CreateMutexTrait {
+ static Mutex* Create() {
+ return OS::CreateMutex();
+ }
+};
+
+// POD Mutex initialized lazily (i.e. the first time Pointer() is called).
+// Usage:
+// static LazyMutex my_mutex = LAZY_MUTEX_INITIALIZER;
+//
+// void my_function() {
+// ScopedLock my_lock(my_mutex.Pointer());
+// // Do something.
+// }
+//
+typedef LazyDynamicInstance<Mutex, CreateMutexTrait>::type LazyMutex;
+
+#define LAZY_MUTEX_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER
// ----------------------------------------------------------------------------
// ScopedLock
@@ -577,6 +597,30 @@
virtual void Signal() = 0;
};
+template <int InitialValue>
+struct CreateSemaphoreTrait {
+ static Semaphore* Create() {
+ return OS::CreateSemaphore(InitialValue);
+ }
+};
+
+// POD Semaphore initialized lazily (i.e. the first time Pointer() is called).
+// Usage:
+// // The following semaphore starts at 0.
+// static LazySemaphore<0>::type my_semaphore = LAZY_SEMAPHORE_INITIALIZER;
+//
+// void my_function() {
+// // Do something with my_semaphore.Pointer().
+// }
+//
+template <int InitialValue>
+struct LazySemaphore {
+ typedef typename LazyDynamicInstance<
+ Semaphore, CreateSemaphoreTrait<InitialValue> >::type type;
+};
+
+#define LAZY_SEMAPHORE_INITIALIZER LAZY_DYNAMIC_INSTANCE_INITIALIZER
+
// ----------------------------------------------------------------------------
// Socket
diff --git a/src/preparse-data.h b/src/preparse-data.h
index c77a47a..f347430 100644
--- a/src/preparse-data.h
+++ b/src/preparse-data.h
@@ -53,7 +53,7 @@
// Logs a symbol creation of a literal or identifier.
virtual void LogAsciiSymbol(int start, Vector<const char> literal) { }
- virtual void LogUC16Symbol(int start, Vector<const uc16> literal) { }
+ virtual void LogUtf16Symbol(int start, Vector<const uc16> literal) { }
// Logs an error message and marks the log as containing an error.
// Further logging will be ignored, and ExtractData will return a vector
@@ -149,7 +149,7 @@
public:
PartialParserRecorder() : FunctionLoggingParserRecorder() { }
virtual void LogAsciiSymbol(int start, Vector<const char> literal) { }
- virtual void LogUC16Symbol(int start, Vector<const uc16> literal) { }
+ virtual void LogUtf16Symbol(int start, Vector<const uc16> literal) { }
virtual ~PartialParserRecorder() { }
virtual Vector<unsigned> ExtractData();
virtual int symbol_position() { return 0; }
@@ -171,7 +171,7 @@
LogSymbol(start, hash, true, Vector<const byte>::cast(literal));
}
- virtual void LogUC16Symbol(int start, Vector<const uc16> literal) {
+ virtual void LogUtf16Symbol(int start, Vector<const uc16> literal) {
if (!is_recording_) return;
int hash = vector_hash(literal);
LogSymbol(start, hash, false, Vector<const byte>::cast(literal));
diff --git a/src/preparser-api.cc b/src/preparser-api.cc
index 1bca9a3..6e8556a 100644
--- a/src/preparser-api.cc
+++ b/src/preparser-api.cc
@@ -46,10 +46,10 @@
namespace internal {
// UTF16Buffer based on a v8::UnicodeInputStream.
-class InputStreamUTF16Buffer : public UC16CharacterStream {
+class InputStreamUtf16Buffer : public Utf16CharacterStream {
public:
- /* The InputStreamUTF16Buffer maintains an internal buffer
- * that is filled in chunks from the UC16CharacterStream.
+ /* The InputStreamUtf16Buffer maintains an internal buffer
+ * that is filled in chunks from the Utf16CharacterStream.
* It also maintains unlimited pushback capability, but optimized
* for small pushbacks.
* The pushback_buffer_ pointer points to the limit of pushbacks
@@ -60,8 +60,8 @@
* new buffer. When this buffer is read to the end again, the cursor is
* switched back to the internal buffer
*/
- explicit InputStreamUTF16Buffer(v8::UnicodeInputStream* stream)
- : UC16CharacterStream(),
+ explicit InputStreamUtf16Buffer(v8::UnicodeInputStream* stream)
+ : Utf16CharacterStream(),
stream_(stream),
pushback_buffer_(buffer_),
pushback_buffer_end_cache_(NULL),
@@ -70,7 +70,7 @@
buffer_cursor_ = buffer_end_ = buffer_ + kPushBackSize;
}
- virtual ~InputStreamUTF16Buffer() {
+ virtual ~InputStreamUtf16Buffer() {
if (pushback_buffer_backing_ != NULL) {
DeleteArray(pushback_buffer_backing_);
}
@@ -127,12 +127,18 @@
uc16* buffer_start = buffer_ + kPushBackSize;
buffer_cursor_ = buffer_end_ = buffer_start;
while ((value = stream_->Next()) >= 0) {
- if (value > static_cast<int32_t>(unibrow::Utf8::kMaxThreeByteChar)) {
- value = unibrow::Utf8::kBadChar;
+ if (value >
+ static_cast<int32_t>(unibrow::Utf16::kMaxNonSurrogateCharCode)) {
+ buffer_start[buffer_end_++ - buffer_start] =
+ unibrow::Utf16::LeadSurrogate(value);
+ buffer_start[buffer_end_++ - buffer_start] =
+ unibrow::Utf16::TrailSurrogate(value);
+ } else {
+ // buffer_end_ is a const pointer, but buffer_ is writable.
+ buffer_start[buffer_end_++ - buffer_start] = static_cast<uc16>(value);
}
- // buffer_end_ is a const pointer, but buffer_ is writable.
- buffer_start[buffer_end_++ - buffer_start] = static_cast<uc16>(value);
- if (buffer_end_ == buffer_ + kPushBackSize + kBufferSize) break;
+ // Stop one before the end of the buffer in case we get a surrogate pair.
+ if (buffer_end_ <= buffer_ + 1 + kPushBackSize + kBufferSize) break;
}
return buffer_end_ > buffer_start;
}
@@ -179,7 +185,7 @@
PreParserData Preparse(UnicodeInputStream* input, size_t max_stack) {
- internal::InputStreamUTF16Buffer buffer(input);
+ internal::InputStreamUtf16Buffer buffer(input);
uintptr_t stack_limit = reinterpret_cast<uintptr_t>(&buffer) - max_stack;
internal::UnicodeCache unicode_cache;
internal::Scanner scanner(&unicode_cache);
diff --git a/src/preparser.cc b/src/preparser.cc
index b36f4fa..20d3b9c 100644
--- a/src/preparser.cc
+++ b/src/preparser.cc
@@ -1214,7 +1214,7 @@
old_type = finder->AddAsciiSymbol(scanner_->literal_ascii_string(),
type);
} else {
- old_type = finder->AddUC16Symbol(scanner_->literal_uc16_string(), type);
+ old_type = finder->AddUtf16Symbol(scanner_->literal_utf16_string(), type);
}
if (HasConflict(old_type, type)) {
if (IsDataDataConflict(old_type, type)) {
@@ -1387,7 +1387,7 @@
duplicate_finder.AddAsciiSymbol(scanner_->literal_ascii_string(), 1);
} else {
prev_value =
- duplicate_finder.AddUC16Symbol(scanner_->literal_uc16_string(), 1);
+ duplicate_finder.AddUtf16Symbol(scanner_->literal_utf16_string(), 1);
}
if (prev_value != 0) {
@@ -1485,7 +1485,7 @@
if (scanner_->is_literal_ascii()) {
log_->LogAsciiSymbol(identifier_pos, scanner_->literal_ascii_string());
} else {
- log_->LogUC16Symbol(identifier_pos, scanner_->literal_uc16_string());
+ log_->LogUtf16Symbol(identifier_pos, scanner_->literal_utf16_string());
}
}
@@ -1657,7 +1657,7 @@
return AddSymbol(i::Vector<const byte>::cast(key), true, value);
}
-int DuplicateFinder::AddUC16Symbol(i::Vector<const uint16_t> key, int value) {
+int DuplicateFinder::AddUtf16Symbol(i::Vector<const uint16_t> key, int value) {
return AddSymbol(i::Vector<const byte>::cast(key), false, value);
}
diff --git a/src/preparser.h b/src/preparser.h
index 1455561..f3a4347 100644
--- a/src/preparser.h
+++ b/src/preparser.h
@@ -65,7 +65,7 @@
map_(&Match) { }
int AddAsciiSymbol(i::Vector<const char> key, int value);
- int AddUC16Symbol(i::Vector<const uint16_t> key, int value);
+ int AddUtf16Symbol(i::Vector<const uint16_t> key, int value);
// Add a a number literal by converting it (if necessary)
// to the string that ToString(ToNumber(literal)) would generate.
// and then adding that string with AddAsciiSymbol.
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index 70586aa..bb7a7d7 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -72,9 +72,9 @@
Atomic32 RuntimeProfiler::state_ = 0;
-// TODO(isolates): Create the semaphore lazily and clean it up when no
-// longer required.
-Semaphore* RuntimeProfiler::semaphore_ = OS::CreateSemaphore(0);
+
+// TODO(isolates): Clean up the semaphore when it is no longer required.
+static LazySemaphore<0>::type semaphore = LAZY_SEMAPHORE_INITIALIZER;
#ifdef DEBUG
bool RuntimeProfiler::has_been_globally_set_up_ = false;
@@ -406,7 +406,7 @@
// undid the decrement done by the profiler thread. Increment again
// to get the right count of active isolates.
NoBarrier_AtomicIncrement(&state_, 1);
- semaphore_->Signal();
+ semaphore.Pointer()->Signal();
}
@@ -419,7 +419,7 @@
Atomic32 old_state = NoBarrier_CompareAndSwap(&state_, 0, -1);
ASSERT(old_state >= -1);
if (old_state != 0) return false;
- semaphore_->Wait();
+ semaphore.Pointer()->Wait();
return true;
}
@@ -435,7 +435,7 @@
if (new_state == 0) {
// The profiler thread is waiting. Wake it up. It must check for
// stop conditions before attempting to wait again.
- semaphore_->Signal();
+ semaphore.Pointer()->Signal();
}
thread->Join();
// The profiler thread is now stopped. Undo the increment in case it
diff --git a/src/runtime-profiler.h b/src/runtime-profiler.h
index f7ca3f0..e338849 100644
--- a/src/runtime-profiler.h
+++ b/src/runtime-profiler.h
@@ -136,7 +136,6 @@
// -1 => the profiler thread is waiting on the semaphore
// 0 or positive => the number of isolates running JavaScript code.
static Atomic32 state_;
- static Semaphore* semaphore_;
#ifdef DEBUG
static bool has_been_globally_set_up_;
diff --git a/src/runtime.cc b/src/runtime.cc
index cc5aeab..f9e882e 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -7441,9 +7441,11 @@
if (y == y_int) {
result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
} else if (y == 0.5) {
- result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
+ result = (isinf(x)) ? V8_INFINITY
+ : fast_sqrt(x + 0.0); // Convert -0 to +0.
} else if (y == -0.5) {
- result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
+ result = (isinf(x)) ? 0
+ : 1.0 / fast_sqrt(x + 0.0); // Convert -0 to +0.
} else {
result = power_double_double(x, y);
}
@@ -7529,7 +7531,7 @@
isolate->counters()->math_sqrt()->Increment();
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
- return isolate->heap()->AllocateHeapNumber(sqrt(x));
+ return isolate->heap()->AllocateHeapNumber(fast_sqrt(x));
}
@@ -8112,25 +8114,8 @@
};
-RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
- HandleScope scope(isolate);
- ASSERT(args.length() == 1);
- RUNTIME_ASSERT(args[0]->IsSmi());
- Deoptimizer::BailoutType type =
- static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
- Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
- ASSERT(isolate->heap()->IsAllocationAllowed());
- int jsframes = deoptimizer->jsframe_count();
-
- deoptimizer->MaterializeHeapNumbers();
- delete deoptimizer;
-
- JavaScriptFrameIterator it(isolate);
- JavaScriptFrame* frame = NULL;
- for (int i = 0; i < jsframes - 1; i++) it.Advance();
- frame = it.frame();
-
- RUNTIME_ASSERT(frame->function()->IsJSFunction());
+static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
+ JavaScriptFrame* frame) {
Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
Handle<Object> arguments;
for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
@@ -8147,6 +8132,32 @@
frame->SetExpression(i, *arguments);
}
}
+}
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
+ HandleScope scope(isolate);
+ ASSERT(args.length() == 1);
+ RUNTIME_ASSERT(args[0]->IsSmi());
+ Deoptimizer::BailoutType type =
+ static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
+ Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
+ ASSERT(isolate->heap()->IsAllocationAllowed());
+ int jsframes = deoptimizer->jsframe_count();
+
+ deoptimizer->MaterializeHeapNumbers();
+ delete deoptimizer;
+
+ JavaScriptFrameIterator it(isolate);
+ for (int i = 0; i < jsframes - 1; i++) {
+ MaterializeArgumentsObjectInFrame(isolate, it.frame());
+ it.Advance();
+ }
+
+ JavaScriptFrame* frame = it.frame();
+ RUNTIME_ASSERT(frame->function()->IsJSFunction());
+ Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
+ MaterializeArgumentsObjectInFrame(isolate, frame);
if (type == Deoptimizer::EAGER) {
RUNTIME_ASSERT(function->IsOptimized());
diff --git a/src/scanner-character-streams.cc b/src/scanner-character-streams.cc
index ee10703..56b9f03 100644
--- a/src/scanner-character-streams.cc
+++ b/src/scanner-character-streams.cc
@@ -36,19 +36,19 @@
namespace internal {
// ----------------------------------------------------------------------------
-// BufferedUC16CharacterStreams
+// BufferedUtf16CharacterStreams
-BufferedUC16CharacterStream::BufferedUC16CharacterStream()
- : UC16CharacterStream(),
+BufferedUtf16CharacterStream::BufferedUtf16CharacterStream()
+ : Utf16CharacterStream(),
pushback_limit_(NULL) {
// Initialize buffer as being empty. First read will fill the buffer.
buffer_cursor_ = buffer_;
buffer_end_ = buffer_;
}
-BufferedUC16CharacterStream::~BufferedUC16CharacterStream() { }
+BufferedUtf16CharacterStream::~BufferedUtf16CharacterStream() { }
-void BufferedUC16CharacterStream::PushBack(uc32 character) {
+void BufferedUtf16CharacterStream::PushBack(uc32 character) {
if (character == kEndOfInput) {
pos_--;
return;
@@ -63,7 +63,7 @@
}
-void BufferedUC16CharacterStream::SlowPushBack(uc16 character) {
+void BufferedUtf16CharacterStream::SlowPushBack(uc16 character) {
// In pushback mode, the end of the buffer contains pushback,
// and the start of the buffer (from buffer start to pushback_limit_)
// contains valid data that comes just after the pushback.
@@ -89,7 +89,7 @@
}
-bool BufferedUC16CharacterStream::ReadBlock() {
+bool BufferedUtf16CharacterStream::ReadBlock() {
buffer_cursor_ = buffer_;
if (pushback_limit_ != NULL) {
// Leave pushback mode.
@@ -106,7 +106,7 @@
}
-unsigned BufferedUC16CharacterStream::SlowSeekForward(unsigned delta) {
+unsigned BufferedUtf16CharacterStream::SlowSeekForward(unsigned delta) {
// Leave pushback mode (i.e., ignore that there might be valid data
// in the buffer before the pushback_limit_ point).
pushback_limit_ = NULL;
@@ -114,10 +114,10 @@
}
// ----------------------------------------------------------------------------
-// GenericStringUC16CharacterStream
+// GenericStringUtf16CharacterStream
-GenericStringUC16CharacterStream::GenericStringUC16CharacterStream(
+GenericStringUtf16CharacterStream::GenericStringUtf16CharacterStream(
Handle<String> data,
unsigned start_position,
unsigned end_position)
@@ -130,10 +130,10 @@
}
-GenericStringUC16CharacterStream::~GenericStringUC16CharacterStream() { }
+GenericStringUtf16CharacterStream::~GenericStringUtf16CharacterStream() { }
-unsigned GenericStringUC16CharacterStream::BufferSeekForward(unsigned delta) {
+unsigned GenericStringUtf16CharacterStream::BufferSeekForward(unsigned delta) {
unsigned old_pos = pos_;
pos_ = Min(pos_ + delta, length_);
ReadBlock();
@@ -141,7 +141,7 @@
}
-unsigned GenericStringUC16CharacterStream::FillBuffer(unsigned from_pos,
+unsigned GenericStringUtf16CharacterStream::FillBuffer(unsigned from_pos,
unsigned length) {
if (from_pos >= length_) return 0;
if (from_pos + length > length_) {
@@ -153,10 +153,10 @@
// ----------------------------------------------------------------------------
-// Utf8ToUC16CharacterStream
-Utf8ToUC16CharacterStream::Utf8ToUC16CharacterStream(const byte* data,
- unsigned length)
- : BufferedUC16CharacterStream(),
+// Utf8ToUtf16CharacterStream
+Utf8ToUtf16CharacterStream::Utf8ToUtf16CharacterStream(const byte* data,
+ unsigned length)
+ : BufferedUtf16CharacterStream(),
raw_data_(data),
raw_data_length_(length),
raw_data_pos_(0),
@@ -165,10 +165,10 @@
}
-Utf8ToUC16CharacterStream::~Utf8ToUC16CharacterStream() { }
+Utf8ToUtf16CharacterStream::~Utf8ToUtf16CharacterStream() { }
-unsigned Utf8ToUC16CharacterStream::BufferSeekForward(unsigned delta) {
+unsigned Utf8ToUtf16CharacterStream::BufferSeekForward(unsigned delta) {
unsigned old_pos = pos_;
unsigned target_pos = pos_ + delta;
SetRawPosition(target_pos);
@@ -178,9 +178,9 @@
}
-unsigned Utf8ToUC16CharacterStream::FillBuffer(unsigned char_position,
- unsigned length) {
- static const unibrow::uchar kMaxUC16Character = 0xffff;
+unsigned Utf8ToUtf16CharacterStream::FillBuffer(unsigned char_position,
+ unsigned length) {
+ static const unibrow::uchar kMaxUtf16Character = 0xffff;
SetRawPosition(char_position);
if (raw_character_position_ != char_position) {
// char_position was not a valid position in the stream (hit the end
@@ -188,7 +188,7 @@
return 0u;
}
unsigned i = 0;
- while (i < length) {
+ while (i < length - 1) {
if (raw_data_pos_ == raw_data_length_) break;
unibrow::uchar c = raw_data_[raw_data_pos_];
if (c <= unibrow::Utf8::kMaxOneByteChar) {
@@ -197,12 +197,13 @@
c = unibrow::Utf8::CalculateValue(raw_data_ + raw_data_pos_,
raw_data_length_ - raw_data_pos_,
&raw_data_pos_);
- // Don't allow characters outside of the BMP.
- if (c > kMaxUC16Character) {
- c = unibrow::Utf8::kBadChar;
- }
}
- buffer_[i++] = static_cast<uc16>(c);
+ if (c > kMaxUtf16Character) {
+ buffer_[i++] = unibrow::Utf16::LeadSurrogate(c);
+ buffer_[i++] = unibrow::Utf16::TrailSurrogate(c);
+ } else {
+ buffer_[i++] = static_cast<uc16>(c);
+ }
}
raw_character_position_ = char_position + i;
return i;
@@ -266,37 +267,52 @@
}
-void Utf8ToUC16CharacterStream::SetRawPosition(unsigned target_position) {
+// This can't set a raw position between two surrogate pairs, since there
+// is no position in the UTF8 stream that corresponds to that. This assumes
+// that the surrogate pair is correctly coded as a 4 byte UTF-8 sequence. If
+// it is illegally coded as two 3 byte sequences then there is no problem here.
+void Utf8ToUtf16CharacterStream::SetRawPosition(unsigned target_position) {
if (raw_character_position_ > target_position) {
// Spool backwards in utf8 buffer.
do {
+ int old_pos = raw_data_pos_;
Utf8CharacterBack(raw_data_, &raw_data_pos_);
raw_character_position_--;
+ ASSERT(old_pos - raw_data_pos_ <= 4);
+ // Step back over both code units for surrogate pairs.
+ if (old_pos - raw_data_pos_ == 4) raw_character_position_--;
} while (raw_character_position_ > target_position);
+ // No surrogate pair splitting.
+ ASSERT(raw_character_position_ == target_position);
return;
}
// Spool forwards in the utf8 buffer.
while (raw_character_position_ < target_position) {
if (raw_data_pos_ == raw_data_length_) return;
+ int old_pos = raw_data_pos_;
Utf8CharacterForward(raw_data_, &raw_data_pos_);
raw_character_position_++;
+ ASSERT(raw_data_pos_ - old_pos <= 4);
+ if (raw_data_pos_ - old_pos == 4) raw_character_position_++;
}
+ // No surrogate pair splitting.
+ ASSERT(raw_character_position_ == target_position);
}
// ----------------------------------------------------------------------------
-// ExternalTwoByteStringUC16CharacterStream
+// ExternalTwoByteStringUtf16CharacterStream
-ExternalTwoByteStringUC16CharacterStream::
- ~ExternalTwoByteStringUC16CharacterStream() { }
+ExternalTwoByteStringUtf16CharacterStream::
+ ~ExternalTwoByteStringUtf16CharacterStream() { }
-ExternalTwoByteStringUC16CharacterStream
- ::ExternalTwoByteStringUC16CharacterStream(
+ExternalTwoByteStringUtf16CharacterStream
+ ::ExternalTwoByteStringUtf16CharacterStream(
Handle<ExternalTwoByteString> data,
int start_position,
int end_position)
- : UC16CharacterStream(),
+ : Utf16CharacterStream(),
source_(data),
raw_data_(data->GetTwoByteData(start_position)) {
buffer_cursor_ = raw_data_,
diff --git a/src/scanner-character-streams.h b/src/scanner-character-streams.h
index 5c4ea2c..319ee8f 100644
--- a/src/scanner-character-streams.h
+++ b/src/scanner-character-streams.h
@@ -36,10 +36,10 @@
// A buffered character stream based on a random access character
// source (ReadBlock can be called with pos_ pointing to any position,
// even positions before the current).
-class BufferedUC16CharacterStream: public UC16CharacterStream {
+class BufferedUtf16CharacterStream: public Utf16CharacterStream {
public:
- BufferedUC16CharacterStream();
- virtual ~BufferedUC16CharacterStream();
+ BufferedUtf16CharacterStream();
+ virtual ~BufferedUtf16CharacterStream();
virtual void PushBack(uc32 character);
@@ -60,12 +60,12 @@
// Generic string stream.
-class GenericStringUC16CharacterStream: public BufferedUC16CharacterStream {
+class GenericStringUtf16CharacterStream: public BufferedUtf16CharacterStream {
public:
- GenericStringUC16CharacterStream(Handle<String> data,
- unsigned start_position,
- unsigned end_position);
- virtual ~GenericStringUC16CharacterStream();
+ GenericStringUtf16CharacterStream(Handle<String> data,
+ unsigned start_position,
+ unsigned end_position);
+ virtual ~GenericStringUtf16CharacterStream();
protected:
virtual unsigned BufferSeekForward(unsigned delta);
@@ -77,11 +77,11 @@
};
-// UC16 stream based on a literal UTF-8 string.
-class Utf8ToUC16CharacterStream: public BufferedUC16CharacterStream {
+// Utf16 stream based on a literal UTF-8 string.
+class Utf8ToUtf16CharacterStream: public BufferedUtf16CharacterStream {
public:
- Utf8ToUC16CharacterStream(const byte* data, unsigned length);
- virtual ~Utf8ToUC16CharacterStream();
+ Utf8ToUtf16CharacterStream(const byte* data, unsigned length);
+ virtual ~Utf8ToUtf16CharacterStream();
protected:
virtual unsigned BufferSeekForward(unsigned delta);
@@ -98,12 +98,12 @@
// UTF16 buffer to read characters from an external string.
-class ExternalTwoByteStringUC16CharacterStream: public UC16CharacterStream {
+class ExternalTwoByteStringUtf16CharacterStream: public Utf16CharacterStream {
public:
- ExternalTwoByteStringUC16CharacterStream(Handle<ExternalTwoByteString> data,
- int start_position,
- int end_position);
- virtual ~ExternalTwoByteStringUC16CharacterStream();
+ ExternalTwoByteStringUtf16CharacterStream(Handle<ExternalTwoByteString> data,
+ int start_position,
+ int end_position);
+ virtual ~ExternalTwoByteStringUtf16CharacterStream();
virtual void PushBack(uc32 character) {
ASSERT(buffer_cursor_ > raw_data_);
diff --git a/src/scanner.cc b/src/scanner.cc
index 72768b3..7901b5d 100755
--- a/src/scanner.cc
+++ b/src/scanner.cc
@@ -45,7 +45,7 @@
harmony_modules_(false) { }
-void Scanner::Initialize(UC16CharacterStream* source) {
+void Scanner::Initialize(Utf16CharacterStream* source) {
source_ = source;
// Need to capture identifiers in order to recognize "get" and "set"
// in object literals.
diff --git a/src/scanner.h b/src/scanner.h
index e892fe0..045e7d2 100644
--- a/src/scanner.h
+++ b/src/scanner.h
@@ -73,15 +73,17 @@
// ---------------------------------------------------------------------
-// Buffered stream of characters, using an internal UC16 buffer.
+// Buffered stream of UTF-16 code units, using an internal UTF-16 buffer.
+// A code unit is a 16 bit value representing either a 16 bit code point
+// or one part of a surrogate pair that make a single 21 bit code point.
-class UC16CharacterStream {
+class Utf16CharacterStream {
public:
- UC16CharacterStream() : pos_(0) { }
- virtual ~UC16CharacterStream() { }
+ Utf16CharacterStream() : pos_(0) { }
+ virtual ~Utf16CharacterStream() { }
- // Returns and advances past the next UC16 character in the input
- // stream. If there are no more characters, it returns a negative
+ // Returns and advances past the next UTF-16 code unit in the input
+ // stream. If there are no more code units, it returns a negative
// value.
inline uc32 Advance() {
if (buffer_cursor_ < buffer_end_ || ReadBlock()) {
@@ -90,47 +92,47 @@
}
// Note: currently the following increment is necessary to avoid a
// parser problem! The scanner treats the final kEndOfInput as
- // a character with a position, and does math relative to that
+ // a code unit with a position, and does math relative to that
// position.
pos_++;
return kEndOfInput;
}
- // Return the current position in the character stream.
+ // Return the current position in the code unit stream.
// Starts at zero.
inline unsigned pos() const { return pos_; }
- // Skips forward past the next character_count UC16 characters
+ // Skips forward past the next code_unit_count UTF-16 code units
// in the input, or until the end of input if that comes sooner.
- // Returns the number of characters actually skipped. If less
- // than character_count,
- inline unsigned SeekForward(unsigned character_count) {
+ // Returns the number of code units actually skipped. If less
+ // than code_unit_count,
+ inline unsigned SeekForward(unsigned code_unit_count) {
unsigned buffered_chars =
static_cast<unsigned>(buffer_end_ - buffer_cursor_);
- if (character_count <= buffered_chars) {
- buffer_cursor_ += character_count;
- pos_ += character_count;
- return character_count;
+ if (code_unit_count <= buffered_chars) {
+ buffer_cursor_ += code_unit_count;
+ pos_ += code_unit_count;
+ return code_unit_count;
}
- return SlowSeekForward(character_count);
+ return SlowSeekForward(code_unit_count);
}
- // Pushes back the most recently read UC16 character (or negative
+ // Pushes back the most recently read UTF-16 code unit (or negative
// value if at end of input), i.e., the value returned by the most recent
// call to Advance.
// Must not be used right after calling SeekForward.
- virtual void PushBack(int32_t character) = 0;
+ virtual void PushBack(int32_t code_unit) = 0;
protected:
static const uc32 kEndOfInput = -1;
- // Ensures that the buffer_cursor_ points to the character at
+ // Ensures that the buffer_cursor_ points to the code_unit at
// position pos_ of the input, if possible. If the position
// is at or after the end of the input, return false. If there
- // are more characters available, return true.
+ // are more code_units available, return true.
virtual bool ReadBlock() = 0;
- virtual unsigned SlowSeekForward(unsigned character_count) = 0;
+ virtual unsigned SlowSeekForward(unsigned code_unit_count) = 0;
const uc16* buffer_cursor_;
const uc16* buffer_end_;
@@ -178,23 +180,24 @@
}
}
- INLINE(void AddChar(uc16 character)) {
+ INLINE(void AddChar(uint32_t code_unit)) {
if (position_ >= backing_store_.length()) ExpandBuffer();
if (is_ascii_) {
- if (character < kMaxAsciiCharCodeU) {
- backing_store_[position_] = static_cast<byte>(character);
+ if (code_unit < kMaxAsciiCharCodeU) {
+ backing_store_[position_] = static_cast<byte>(code_unit);
position_ += kASCIISize;
return;
}
- ConvertToUC16();
+ ConvertToUtf16();
}
- *reinterpret_cast<uc16*>(&backing_store_[position_]) = character;
+ ASSERT(code_unit < 0x10000u);
+ *reinterpret_cast<uc16*>(&backing_store_[position_]) = code_unit;
position_ += kUC16Size;
}
bool is_ascii() { return is_ascii_; }
- Vector<const uc16> uc16_literal() {
+ Vector<const uc16> utf16_literal() {
ASSERT(!is_ascii_);
ASSERT((position_ & 0x1) == 0);
return Vector<const uc16>(
@@ -236,13 +239,13 @@
backing_store_ = new_store;
}
- void ConvertToUC16() {
+ void ConvertToUtf16() {
ASSERT(is_ascii_);
Vector<byte> new_store;
int new_content_size = position_ * kUC16Size;
if (new_content_size >= backing_store_.length()) {
- // Ensure room for all currently read characters as UC16 as well
- // as the character about to be stored.
+ // Ensure room for all currently read code units as UC16 as well
+ // as the code unit about to be stored.
new_store = Vector<byte>::New(NewCapacity(new_content_size));
} else {
new_store = backing_store_;
@@ -316,7 +319,7 @@
explicit Scanner(UnicodeCache* scanner_contants);
- void Initialize(UC16CharacterStream* source);
+ void Initialize(Utf16CharacterStream* source);
// Returns the next token and advances input.
Token::Value Next();
@@ -335,9 +338,9 @@
ASSERT_NOT_NULL(current_.literal_chars);
return current_.literal_chars->ascii_literal();
}
- Vector<const uc16> literal_uc16_string() {
+ Vector<const uc16> literal_utf16_string() {
ASSERT_NOT_NULL(current_.literal_chars);
- return current_.literal_chars->uc16_literal();
+ return current_.literal_chars->utf16_literal();
}
bool is_literal_ascii() {
ASSERT_NOT_NULL(current_.literal_chars);
@@ -371,9 +374,9 @@
ASSERT_NOT_NULL(next_.literal_chars);
return next_.literal_chars->ascii_literal();
}
- Vector<const uc16> next_literal_uc16_string() {
+ Vector<const uc16> next_literal_utf16_string() {
ASSERT_NOT_NULL(next_.literal_chars);
- return next_.literal_chars->uc16_literal();
+ return next_.literal_chars->utf16_literal();
}
bool is_next_literal_ascii() {
ASSERT_NOT_NULL(next_.literal_chars);
@@ -542,8 +545,8 @@
TokenDesc current_; // desc for current token (as returned by Next())
TokenDesc next_; // desc for next token (one token look-ahead)
- // Input stream. Must be initialized to an UC16CharacterStream.
- UC16CharacterStream* source_;
+ // Input stream. Must be initialized to an Utf16CharacterStream.
+ Utf16CharacterStream* source_;
// Start position of the octal literal last scanned.
diff --git a/src/unicode-inl.h b/src/unicode-inl.h
index c0649d7..9c0ebf9 100644
--- a/src/unicode-inl.h
+++ b/src/unicode-inl.h
@@ -78,7 +78,7 @@
}
-unsigned Utf8::Encode(char* str, uchar c) {
+unsigned Utf8::Encode(char* str, uchar c, int previous) {
static const int kMask = ~(1 << 6);
if (c <= kMaxOneByteChar) {
str[0] = c;
@@ -88,6 +88,13 @@
str[1] = 0x80 | (c & kMask);
return 2;
} else if (c <= kMaxThreeByteChar) {
+ if (Utf16::IsTrailSurrogate(c) &&
+ Utf16::IsLeadSurrogate(previous)) {
+ const int kUnmatchedSize = kSizeOfUnmatchedSurrogate;
+ return Encode(str - kUnmatchedSize,
+ Utf16::CombineSurrogatePair(previous, c),
+ Utf16::kNoPreviousCharacter) - kUnmatchedSize;
+ }
str[0] = 0xE0 | (c >> 12);
str[1] = 0x80 | ((c >> 6) & kMask);
str[2] = 0x80 | (c & kMask);
@@ -113,12 +120,16 @@
return CalculateValue(bytes, length, cursor);
}
-unsigned Utf8::Length(uchar c) {
+unsigned Utf8::Length(uchar c, int previous) {
if (c <= kMaxOneByteChar) {
return 1;
} else if (c <= kMaxTwoByteChar) {
return 2;
} else if (c <= kMaxThreeByteChar) {
+ if (Utf16::IsTrailSurrogate(c) &&
+ Utf16::IsLeadSurrogate(previous)) {
+ return kSizeOfUnmatchedSurrogate - kBytesSavedByCombiningSurrogates;
+ }
return 3;
} else {
return 4;
diff --git a/src/unicode.cc b/src/unicode.cc
index 61c649f..14f3806 100644
--- a/src/unicode.cc
+++ b/src/unicode.cc
@@ -276,6 +276,7 @@
return kBadChar;
}
+
const byte* Utf8::ReadBlock(Buffer<const char*> str, byte* buffer,
unsigned capacity, unsigned* chars_read_ptr, unsigned* offset_ptr) {
unsigned offset = *offset_ptr;
@@ -338,6 +339,16 @@
return result;
}
+unsigned CharacterStream::Utf16Length() {
+ unsigned result = 0;
+ while (has_more()) {
+ uchar c = GetNext();
+ result += c > Utf16::kMaxNonSurrogateCharCode ? 2 : 1;
+ }
+ Rewind();
+ return result;
+}
+
void CharacterStream::Seek(unsigned position) {
Rewind();
for (unsigned i = 0; i < position; i++) {
diff --git a/src/unicode.h b/src/unicode.h
index fb9e633..94ab1b4 100644
--- a/src/unicode.h
+++ b/src/unicode.h
@@ -100,7 +100,7 @@
static const uchar kMaxCodePoint;
};
-// --- U t f 8 ---
+// --- U t f 8 a n d 16 ---
template <typename Data>
class Buffer {
@@ -114,10 +114,46 @@
unsigned length_;
};
+
+class Utf16 {
+ public:
+ static inline bool IsLeadSurrogate(int code) {
+ if (code == kNoPreviousCharacter) return false;
+ return (code & 0xfc00) == 0xd800;
+ }
+ static inline bool IsTrailSurrogate(int code) {
+ if (code == kNoPreviousCharacter) return false;
+ return (code & 0xfc00) == 0xdc00;
+ }
+
+ static inline int CombineSurrogatePair(uchar lead, uchar trail) {
+ return 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
+ }
+ static const int kNoPreviousCharacter = -1;
+ static const uchar kMaxNonSurrogateCharCode = 0xffff;
+ // Encoding a single UTF-16 code unit will produce 1, 2 or 3 bytes
+ // of UTF-8 data. The special case where the unit is a surrogate
+ // trail produces 1 byte net, because the encoding of the pair is
+ // 4 bytes and the 3 bytes that were used to encode the lead surrogate
+ // can be reclaimed.
+ static const int kMaxExtraUtf8BytesForOneUtf16CodeUnit = 3;
+ // One UTF-16 surrogate is endoded (illegally) as 3 UTF-8 bytes.
+ // The illegality stems from the surrogate not being part of a pair.
+ static const int kUtf8BytesToCodeASurrogate = 3;
+ static inline uchar LeadSurrogate(int char_code) {
+ return 0xd800 + (((char_code - 0x10000) >> 10) & 0x3ff);
+ }
+ static inline uchar TrailSurrogate(int char_code) {
+ return 0xdc00 + (char_code & 0x3ff);
+ }
+};
+
+
class Utf8 {
public:
- static inline uchar Length(uchar chr);
- static inline unsigned Encode(char* out, uchar c);
+ static inline uchar Length(uchar chr, int previous);
+ static inline unsigned Encode(
+ char* out, uchar c, int previous);
static const byte* ReadBlock(Buffer<const char*> str, byte* buffer,
unsigned capacity, unsigned* chars_read, unsigned* offset);
static uchar CalculateValue(const byte* str,
@@ -130,6 +166,11 @@
static const unsigned kMaxThreeByteChar = 0xffff;
static const unsigned kMaxFourByteChar = 0x1fffff;
+ // A single surrogate is coded as a 3 byte UTF-8 sequence, but two together
+ // that match are coded as a 4 byte UTF-8 sequence.
+ static const unsigned kBytesSavedByCombiningSurrogates = 2;
+ static const unsigned kSizeOfUnmatchedSurrogate = 3;
+
private:
template <unsigned s> friend class Utf8InputBuffer;
friend class Test;
@@ -147,6 +188,7 @@
// Note that default implementation is not efficient.
virtual void Seek(unsigned);
unsigned Length();
+ unsigned Utf16Length();
virtual ~CharacterStream() { }
static inline bool EncodeCharacter(uchar c, byte* buffer, unsigned capacity,
unsigned& offset);
@@ -156,6 +198,7 @@
unsigned capacity, unsigned& offset);
static inline uchar DecodeCharacter(const byte* buffer, unsigned* offset);
virtual void Rewind() = 0;
+
protected:
virtual void FillBuffer() = 0;
// The number of characters left in the current buffer
diff --git a/src/v8.cc b/src/v8.cc
index 98b3038..506f3f6 100644
--- a/src/v8.cc
+++ b/src/v8.cc
@@ -36,6 +36,8 @@
#include "hydrogen.h"
#include "lithium-allocator.h"
#include "log.h"
+#include "once.h"
+#include "platform.h"
#include "runtime-profiler.h"
#include "serialize.h"
#include "store-buffer.h"
@@ -43,8 +45,7 @@
namespace v8 {
namespace internal {
-static Mutex* init_once_mutex = OS::CreateMutex();
-static bool init_once_called = false;
+V8_DECLARE_ONCE(init_once);
bool V8::is_running_ = false;
bool V8::has_been_set_up_ = false;
@@ -53,7 +54,8 @@
bool V8::use_crankshaft_ = true;
List<CallCompletedCallback>* V8::call_completed_callbacks_ = NULL;
-static Mutex* entropy_mutex = OS::CreateMutex();
+static LazyMutex entropy_mutex = LAZY_MUTEX_INITIALIZER;
+
static EntropySource entropy_source;
@@ -117,7 +119,7 @@
state[i] = FLAG_random_seed;
} else if (entropy_source != NULL) {
uint32_t val;
- ScopedLock lock(entropy_mutex);
+ ScopedLock lock(entropy_mutex.Pointer());
entropy_source(reinterpret_cast<unsigned char*>(&val), sizeof(uint32_t));
state[i] = val;
} else {
@@ -237,12 +239,7 @@
return heap_number;
}
-
-void V8::InitializeOncePerProcess() {
- ScopedLock lock(init_once_mutex);
- if (init_once_called) return;
- init_once_called = true;
-
+void V8::InitializeOncePerProcessImpl() {
// Set up the platform OS support.
OS::SetUp();
@@ -266,6 +263,12 @@
FLAG_gc_global = true;
FLAG_max_new_space_size = (1 << (kPageSizeBits - 10)) * 2;
}
+
+ LOperand::SetUpCaches();
+}
+
+void V8::InitializeOncePerProcess() {
+ CallOnce(&init_once, &InitializeOncePerProcessImpl);
}
} } // namespace v8::internal
diff --git a/src/v8.h b/src/v8.h
index 699c5a0..59ce602 100644
--- a/src/v8.h
+++ b/src/v8.h
@@ -116,6 +116,7 @@
static void FireCallCompletedCallback(Isolate* isolate);
private:
+ static void InitializeOncePerProcessImpl();
static void InitializeOncePerProcess();
// True if engine is currently running
diff --git a/src/version.cc b/src/version.cc
index 57e6594..c7d6356 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 9
-#define BUILD_NUMBER 17
+#define BUILD_NUMBER 18
#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h
index 7af33e1..3725c03 100644
--- a/src/x64/assembler-x64.h
+++ b/src/x64/assembler-x64.h
@@ -161,23 +161,41 @@
static const int kAllocationIndexByRegisterCode[kNumRegisters];
};
-const Register rax = { 0 };
-const Register rcx = { 1 };
-const Register rdx = { 2 };
-const Register rbx = { 3 };
-const Register rsp = { 4 };
-const Register rbp = { 5 };
-const Register rsi = { 6 };
-const Register rdi = { 7 };
-const Register r8 = { 8 };
-const Register r9 = { 9 };
-const Register r10 = { 10 };
-const Register r11 = { 11 };
-const Register r12 = { 12 };
-const Register r13 = { 13 };
-const Register r14 = { 14 };
-const Register r15 = { 15 };
-const Register no_reg = { -1 };
+const int kRegister_rax_Code = 0;
+const int kRegister_rcx_Code = 1;
+const int kRegister_rdx_Code = 2;
+const int kRegister_rbx_Code = 3;
+const int kRegister_rsp_Code = 4;
+const int kRegister_rbp_Code = 5;
+const int kRegister_rsi_Code = 6;
+const int kRegister_rdi_Code = 7;
+const int kRegister_r8_Code = 8;
+const int kRegister_r9_Code = 9;
+const int kRegister_r10_Code = 10;
+const int kRegister_r11_Code = 11;
+const int kRegister_r12_Code = 12;
+const int kRegister_r13_Code = 13;
+const int kRegister_r14_Code = 14;
+const int kRegister_r15_Code = 15;
+const int kRegister_no_reg_Code = -1;
+
+const Register rax = { kRegister_rax_Code };
+const Register rcx = { kRegister_rcx_Code };
+const Register rdx = { kRegister_rdx_Code };
+const Register rbx = { kRegister_rbx_Code };
+const Register rsp = { kRegister_rsp_Code };
+const Register rbp = { kRegister_rbp_Code };
+const Register rsi = { kRegister_rsi_Code };
+const Register rdi = { kRegister_rdi_Code };
+const Register r8 = { kRegister_r8_Code };
+const Register r9 = { kRegister_r9_Code };
+const Register r10 = { kRegister_r10_Code };
+const Register r11 = { kRegister_r11_Code };
+const Register r12 = { kRegister_r12_Code };
+const Register r13 = { kRegister_r13_Code };
+const Register r14 = { kRegister_r14_Code };
+const Register r15 = { kRegister_r15_Code };
+const Register no_reg = { kRegister_no_reg_Code };
struct XMMRegister {
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc
index d616749..2845039 100644
--- a/src/x64/code-stubs-x64.cc
+++ b/src/x64/code-stubs-x64.cc
@@ -5991,42 +5991,45 @@
};
+#define REG(Name) { kRegister_ ## Name ## _Code }
+
struct AheadOfTimeWriteBarrierStubList kAheadOfTime[] = {
// Used in RegExpExecStub.
- { rbx, rax, rdi, EMIT_REMEMBERED_SET },
+ { REG(rbx), REG(rax), REG(rdi), EMIT_REMEMBERED_SET },
// Used in CompileArrayPushCall.
- { rbx, rcx, rdx, EMIT_REMEMBERED_SET },
+ { REG(rbx), REG(rcx), REG(rdx), EMIT_REMEMBERED_SET },
// Used in CompileStoreGlobal.
- { rbx, rcx, rdx, OMIT_REMEMBERED_SET },
+ { REG(rbx), REG(rcx), REG(rdx), OMIT_REMEMBERED_SET },
// Used in StoreStubCompiler::CompileStoreField and
// KeyedStoreStubCompiler::CompileStoreField via GenerateStoreField.
- { rdx, rcx, rbx, EMIT_REMEMBERED_SET },
+ { REG(rdx), REG(rcx), REG(rbx), EMIT_REMEMBERED_SET },
// GenerateStoreField calls the stub with two different permutations of
// registers. This is the second.
- { rbx, rcx, rdx, EMIT_REMEMBERED_SET },
+ { REG(rbx), REG(rcx), REG(rdx), EMIT_REMEMBERED_SET },
// StoreIC::GenerateNormal via GenerateDictionaryStore.
- { rbx, r8, r9, EMIT_REMEMBERED_SET },
+ { REG(rbx), REG(r8), REG(r9), EMIT_REMEMBERED_SET },
// KeyedStoreIC::GenerateGeneric.
- { rbx, rdx, rcx, EMIT_REMEMBERED_SET},
+ { REG(rbx), REG(rdx), REG(rcx), EMIT_REMEMBERED_SET},
// KeyedStoreStubCompiler::GenerateStoreFastElement.
- { rdi, rbx, rcx, EMIT_REMEMBERED_SET},
- { rdx, rdi, rbx, EMIT_REMEMBERED_SET},
+ { REG(rdi), REG(rbx), REG(rcx), EMIT_REMEMBERED_SET},
+ { REG(rdx), REG(rdi), REG(rbx), EMIT_REMEMBERED_SET},
// ElementsTransitionGenerator::GenerateSmiOnlyToObject
// and ElementsTransitionGenerator::GenerateSmiOnlyToObject
// and ElementsTransitionGenerator::GenerateDoubleToObject
- { rdx, rbx, rdi, EMIT_REMEMBERED_SET},
- { rdx, rbx, rdi, OMIT_REMEMBERED_SET},
+ { REG(rdx), REG(rbx), REG(rdi), EMIT_REMEMBERED_SET},
+ { REG(rdx), REG(rbx), REG(rdi), OMIT_REMEMBERED_SET},
// ElementsTransitionGenerator::GenerateSmiOnlyToDouble
// and ElementsTransitionGenerator::GenerateDoubleToObject
- { rdx, r11, r15, EMIT_REMEMBERED_SET},
+ { REG(rdx), REG(r11), REG(r15), EMIT_REMEMBERED_SET},
// ElementsTransitionGenerator::GenerateDoubleToObject
- { r11, rax, r15, EMIT_REMEMBERED_SET},
+ { REG(r11), REG(rax), REG(r15), EMIT_REMEMBERED_SET},
// StoreArrayLiteralElementStub::Generate
- { rbx, rax, rcx, EMIT_REMEMBERED_SET},
+ { REG(rbx), REG(rax), REG(rcx), EMIT_REMEMBERED_SET},
// Null termination.
- { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET}
+ { REG(no_reg), REG(no_reg), REG(no_reg), EMIT_REMEMBERED_SET}
};
+#undef REG
bool RecordWriteStub::IsPregenerated() {
for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime;
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 902f7e9..a8d39b2 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -55,8 +55,7 @@
#define __ masm.
-TranscendentalFunction CreateTranscendentalFunction(
- TranscendentalCache::Type type) {
+UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) {
size_t actual_size;
// Allocate buffer in executable space.
byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
@@ -96,7 +95,31 @@
CPU::FlushICache(buffer, actual_size);
OS::ProtectCode(buffer, actual_size);
- return FUNCTION_CAST<TranscendentalFunction>(buffer);
+ return FUNCTION_CAST<UnaryMathFunction>(buffer);
+}
+
+
+UnaryMathFunction CreateSqrtFunction() {
+ size_t actual_size;
+ // Allocate buffer in executable space.
+ byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB,
+ &actual_size,
+ true));
+ if (buffer == NULL) return &sqrt;
+
+ MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+ // xmm0: raw double input.
+ // Move double input into registers.
+ __ sqrtsd(xmm0, xmm0);
+ __ Ret();
+
+ CodeDesc desc;
+ masm.GetCode(&desc);
+ ASSERT(desc.reloc_size == 0);
+
+ CPU::FlushICache(buffer, actual_size);
+ OS::ProtectCode(buffer, actual_size);
+ return FUNCTION_CAST<UnaryMathFunction>(buffer);
}
diff --git a/src/x64/disasm-x64.cc b/src/x64/disasm-x64.cc
index 5cbdad7..adeda0b 100644
--- a/src/x64/disasm-x64.cc
+++ b/src/x64/disasm-x64.cc
@@ -34,6 +34,7 @@
#if defined(V8_TARGET_ARCH_X64)
#include "disasm.h"
+#include "lazy-instance.h"
namespace disasm {
@@ -269,7 +270,8 @@
}
-static InstructionTable instruction_table;
+static v8::internal::LazyInstance<InstructionTable>::type instruction_table =
+ LAZY_INSTANCE_INITIALIZER;
static InstructionDesc cmov_instructions[16] = {
@@ -1338,7 +1340,7 @@
data++;
}
- const InstructionDesc& idesc = instruction_table.Get(current);
+ const InstructionDesc& idesc = instruction_table.Get().Get(current);
byte_size_operand_ = idesc.byte_size_operation;
switch (idesc.type) {
case ZERO_OPERANDS_INSTR:
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index f707df0..20b9748 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -2544,14 +2544,9 @@
}
-void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
+void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
Register receiver = ToRegister(instr->receiver());
Register function = ToRegister(instr->function());
- Register length = ToRegister(instr->length());
- Register elements = ToRegister(instr->elements());
- ASSERT(receiver.is(rax)); // Used for parameter count.
- ASSERT(function.is(rdi)); // Required by InvokeFunction.
- ASSERT(ToRegister(instr->result()).is(rax));
// If the receiver is null or undefined, we have to pass the global
// object as a receiver to normal functions. Values have to be
@@ -2594,6 +2589,17 @@
__ movq(receiver,
FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
__ bind(&receiver_ok);
+}
+
+
+void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
+ Register receiver = ToRegister(instr->receiver());
+ Register function = ToRegister(instr->function());
+ Register length = ToRegister(instr->length());
+ Register elements = ToRegister(instr->elements());
+ ASSERT(receiver.is(rax)); // Used for parameter count.
+ ASSERT(function.is(rdi)); // Required by InvokeFunction.
+ ASSERT(ToRegister(instr->result()).is(rax));
// Copy the arguments to this function possibly from the
// adaptor frame below it.
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index e2569c9..d3e4cdd 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -1092,6 +1092,14 @@
}
+LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
+ LOperand* receiver = UseRegister(instr->receiver());
+ LOperand* function = UseRegisterAtStart(instr->function());
+ LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
+ return AssignEnvironment(DefineSameAsFirst(result));
+}
+
+
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
LOperand* function = UseFixed(instr->function(), rdi);
LOperand* receiver = UseFixed(instr->receiver(), rax);
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 3d5d854..2d8fd2e 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -178,7 +178,8 @@
V(ForInCacheArray) \
V(CheckMapValue) \
V(LoadFieldByIndex) \
- V(DateField)
+ V(DateField) \
+ V(WrapReceiver)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
@@ -469,6 +470,20 @@
};
+class LWrapReceiver: public LTemplateInstruction<1, 2, 0> {
+ public:
+ LWrapReceiver(LOperand* receiver, LOperand* function) {
+ inputs_[0] = receiver;
+ inputs_[1] = function;
+ }
+
+ DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver")
+
+ LOperand* receiver() { return inputs_[0]; }
+ LOperand* function() { return inputs_[1]; }
+};
+
+
class LApplyArguments: public LTemplateInstruction<1, 4, 0> {
public:
LApplyArguments(LOperand* function,
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 2118886..f7db250 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -799,8 +799,15 @@
}
-static const Register saved_regs[] =
- { rax, rcx, rdx, rbx, rbp, rsi, rdi, r8, r9, r10, r11 };
+#define REG(Name) { kRegister_ ## Name ## _Code }
+
+static const Register saved_regs[] = {
+ REG(rax), REG(rcx), REG(rdx), REG(rbx), REG(rbp), REG(rsi), REG(rdi), REG(r8),
+ REG(r9), REG(r10), REG(r11)
+};
+
+#undef REG
+
static const int kNumberOfSavedRegs = sizeof(saved_regs) / sizeof(Register);
@@ -2418,7 +2425,8 @@
// Order general registers are pushed by Pushad:
// rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15.
-int MacroAssembler::kSafepointPushRegisterIndices[Register::kNumRegisters] = {
+const int
+MacroAssembler::kSafepointPushRegisterIndices[Register::kNumRegisters] = {
0,
1,
2,
diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h
index 86eb312..6bb5cfe 100644
--- a/src/x64/macro-assembler-x64.h
+++ b/src/x64/macro-assembler-x64.h
@@ -1307,7 +1307,7 @@
private:
// Order general registers are pushed by Pushad.
// rax, rcx, rdx, rbx, rsi, rdi, r8, r9, r11, r14, r15.
- static int kSafepointPushRegisterIndices[Register::kNumRegisters];
+ static const int kSafepointPushRegisterIndices[Register::kNumRegisters];
static const int kNumSafepointSavedRegisters = 11;
static const int kSmiShift = kSmiTagSize + kSmiShiftSize;
diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc
index 773fc4c..837c254 100644
--- a/src/x64/regexp-macro-assembler-x64.cc
+++ b/src/x64/regexp-macro-assembler-x64.cc
@@ -564,7 +564,7 @@
uc16 minus,
uc16 mask,
Label* on_not_equal) {
- ASSERT(minus < String::kMaxUC16CharCode);
+ ASSERT(minus < String::kMaxUtf16CodeUnit);
__ lea(rax, Operand(current_character(), -minus));
__ and_(rax, Immediate(mask));
__ cmpl(rax, Immediate(c));
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 5137c65..79818ac 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -5526,6 +5526,17 @@
}
+int GetUtf8Length(Handle<String> str) {
+ int len = str->Utf8Length();
+ if (len < 0) {
+ i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
+ i::FlattenString(istr);
+ len = str->Utf8Length();
+ }
+ return len;
+}
+
+
THREADED_TEST(StringWrite) {
LocalContext context;
v8::HandleScope scope;
@@ -5606,7 +5617,7 @@
CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
memset(utf8buf, 0x1, sizeof(utf8buf));
- len = left_tree->Utf8Length();
+ len = GetUtf8Length(left_tree);
int utf8_expected =
(0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
CHECK_EQ(utf8_expected, len);
@@ -5620,7 +5631,7 @@
CHECK_EQ(1, utf8buf[utf8_expected]);
memset(utf8buf, 0x1, sizeof(utf8buf));
- len = right_tree->Utf8Length();
+ len = GetUtf8Length(right_tree);
CHECK_EQ(utf8_expected, len);
len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
CHECK_EQ(utf8_expected, len);
@@ -5745,6 +5756,217 @@
}
+static void Utf16Helper(
+ LocalContext& context,
+ const char* name,
+ const char* lengths_name,
+ int len) {
+ Local<v8::Array> a =
+ Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
+ Local<v8::Array> alens =
+ Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
+ for (int i = 0; i < len; i++) {
+ Local<v8::String> string =
+ Local<v8::String>::Cast(a->Get(i));
+ Local<v8::Number> expected_len =
+ Local<v8::Number>::Cast(alens->Get(i));
+ int length = GetUtf8Length(string);
+ CHECK_EQ(static_cast<int>(expected_len->Value()), length);
+ }
+}
+
+
+static uint16_t StringGet(Handle<String> str, int index) {
+ i::Handle<i::String> istring =
+ v8::Utils::OpenHandle(String::Cast(*str));
+ return istring->Get(index);
+}
+
+
+static void WriteUtf8Helper(
+ LocalContext& context,
+ const char* name,
+ const char* lengths_name,
+ int len) {
+ Local<v8::Array> b =
+ Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
+ Local<v8::Array> alens =
+ Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
+ char buffer[1000];
+ char buffer2[1000];
+ for (int i = 0; i < len; i++) {
+ Local<v8::String> string =
+ Local<v8::String>::Cast(b->Get(i));
+ Local<v8::Number> expected_len =
+ Local<v8::Number>::Cast(alens->Get(i));
+ int utf8_length = static_cast<int>(expected_len->Value());
+ for (int j = utf8_length + 1; j >= 0; j--) {
+ memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
+ memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
+ int nchars;
+ int utf8_written =
+ string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
+ int utf8_written2 =
+ string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
+ CHECK_GE(utf8_length + 1, utf8_written);
+ CHECK_GE(utf8_length, utf8_written2);
+ for (int k = 0; k < utf8_written2; k++) {
+ CHECK_EQ(buffer[k], buffer2[k]);
+ }
+ CHECK(nchars * 3 >= utf8_written - 1);
+ CHECK(nchars <= utf8_written);
+ if (j == utf8_length + 1) {
+ CHECK_EQ(utf8_written2, utf8_length);
+ CHECK_EQ(utf8_written2 + 1, utf8_written);
+ }
+ CHECK_EQ(buffer[utf8_written], 42);
+ if (j > utf8_length) {
+ if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
+ if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
+ Handle<String> roundtrip = v8_str(buffer);
+ CHECK(roundtrip->Equals(string));
+ } else {
+ if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
+ }
+ if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
+ if (nchars >= 2) {
+ uint16_t trail = StringGet(string, nchars - 1);
+ uint16_t lead = StringGet(string, nchars - 2);
+ if (((lead & 0xfc00) == 0xd800) &&
+ ((trail & 0xfc00) == 0xdc00)) {
+ unsigned char u1 = buffer2[utf8_written2 - 4];
+ unsigned char u2 = buffer2[utf8_written2 - 3];
+ unsigned char u3 = buffer2[utf8_written2 - 2];
+ unsigned char u4 = buffer2[utf8_written2 - 1];
+ CHECK_EQ((u1 & 0xf8), 0xf0);
+ CHECK_EQ((u2 & 0xc0), 0x80);
+ CHECK_EQ((u3 & 0xc0), 0x80);
+ CHECK_EQ((u4 & 0xc0), 0x80);
+ uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
+ CHECK_EQ((u4 & 0x3f), (c & 0x3f));
+ CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
+ CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
+ CHECK_EQ((u1 & 0x3), c >> 18);
+ }
+ }
+ }
+ }
+}
+
+
+THREADED_TEST(Utf16) {
+ LocalContext context;
+ v8::HandleScope scope;
+ CompileRun(
+ "var pad = '01234567890123456789';"
+ "var p = [];"
+ "var plens = [20, 3, 3];"
+ "p.push('01234567890123456789');"
+ "var lead = 0xd800;"
+ "var trail = 0xdc00;"
+ "p.push(String.fromCharCode(0xd800));"
+ "p.push(String.fromCharCode(0xdc00));"
+ "var a = [];"
+ "var b = [];"
+ "var alens = [];"
+ "for (var i = 0; i < 3; i++) {"
+ " p[1] = String.fromCharCode(lead++);"
+ " for (var j = 0; j < 3; j++) {"
+ " p[2] = String.fromCharCode(trail++);"
+ " a.push(p[i] + p[j]);"
+ " b.push(p[i] + p[j]);"
+ " alens.push(plens[i] + plens[j]);"
+ " }"
+ "}"
+ "alens[5] -= 2;" // Here the surrogate pairs match up.
+ "var a2 = [];"
+ "var b2 = [];"
+ "var a2lens = [];"
+ "for (var m = 0; m < 9; m++) {"
+ " for (var n = 0; n < 9; n++) {"
+ " a2.push(a[m] + a[n]);"
+ " b2.push(b[m] + b[n]);"
+ " var utf = alens[m] + alens[n];" // And here.
+ // The 'n's that start with 0xdc.. are 6-8
+ // The 'm's that end with 0xd8.. are 1, 4 and 7
+ " if ((m % 3) == 1 && n >= 6) utf -= 2;"
+ " a2lens.push(utf);"
+ " }"
+ "}");
+ Utf16Helper(context, "a", "alens", 9);
+ Utf16Helper(context, "a2", "a2lens", 81);
+ WriteUtf8Helper(context, "b", "alens", 9);
+ WriteUtf8Helper(context, "b2", "a2lens", 81);
+}
+
+
+static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
+ i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
+ i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
+ return *is1 == *is2;
+}
+
+
+static void SameSymbolHelper(const char* a, const char* b) {
+ Handle<String> symbol1 = v8::String::NewSymbol(a);
+ Handle<String> symbol2 = v8::String::NewSymbol(b);
+ CHECK(SameSymbol(symbol1, symbol2));
+}
+
+
+THREADED_TEST(Utf16Symbol) {
+ LocalContext context;
+ v8::HandleScope scope;
+
+ Handle<String> symbol1 = v8::String::NewSymbol("abc");
+ Handle<String> symbol2 = v8::String::NewSymbol("abc");
+ CHECK(SameSymbol(symbol1, symbol2));
+
+ SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
+ "\355\240\201\355\260\205"); // 2 3-byte surrogates.
+ SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
+ "\360\220\220\206"); // 4 byte encoding.
+ SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
+ "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
+ SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
+ "x\360\220\220\206"); // 4 byte encoding.
+ CompileRun(
+ "var sym0 = 'benedictus';"
+ "var sym0b = 'S\303\270ren';"
+ "var sym1 = '\355\240\201\355\260\207';"
+ "var sym2 = '\360\220\220\210';"
+ "var sym3 = 'x\355\240\201\355\260\207';"
+ "var sym4 = 'x\360\220\220\210';"
+ "if (sym1.length != 2) throw sym1;"
+ "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
+ "if (sym2.length != 2) throw sym2;"
+ "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
+ "if (sym3.length != 3) throw sym3;"
+ "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
+ "if (sym4.length != 3) throw sym4;"
+ "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
+ Handle<String> sym0 = v8::String::NewSymbol("benedictus");
+ Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
+ Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
+ Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
+ Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
+ Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
+ v8::Local<v8::Object> global = context->Global();
+ Local<Value> s0 = global->Get(v8_str("sym0"));
+ Local<Value> s0b = global->Get(v8_str("sym0b"));
+ Local<Value> s1 = global->Get(v8_str("sym1"));
+ Local<Value> s2 = global->Get(v8_str("sym2"));
+ Local<Value> s3 = global->Get(v8_str("sym3"));
+ Local<Value> s4 = global->Get(v8_str("sym4"));
+ CHECK(SameSymbol(sym0, Handle<String>(String::Cast(*s0))));
+ CHECK(SameSymbol(sym0b, Handle<String>(String::Cast(*s0b))));
+ CHECK(SameSymbol(sym1, Handle<String>(String::Cast(*s1))));
+ CHECK(SameSymbol(sym2, Handle<String>(String::Cast(*s2))));
+ CHECK(SameSymbol(sym3, Handle<String>(String::Cast(*s3))));
+ CHECK(SameSymbol(sym4, Handle<String>(String::Cast(*s4))));
+}
+
+
THREADED_TEST(ToArrayIndex) {
v8::HandleScope scope;
LocalContext context;
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index cd8a6af..6bcae7c 100755
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -63,7 +63,7 @@
int length = i::StrLength(key_token.keyword);
CHECK(static_cast<int>(sizeof(buffer)) >= length);
{
- i::Utf8ToUC16CharacterStream stream(keyword, length);
+ i::Utf8ToUtf16CharacterStream stream(keyword, length);
i::Scanner scanner(&unicode_cache);
// The scanner should parse Harmony keywords for this test.
scanner.SetHarmonyScoping(true);
@@ -74,7 +74,7 @@
}
// Removing characters will make keyword matching fail.
{
- i::Utf8ToUC16CharacterStream stream(keyword, length - 1);
+ i::Utf8ToUtf16CharacterStream stream(keyword, length - 1);
i::Scanner scanner(&unicode_cache);
scanner.Initialize(&stream);
CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
@@ -85,7 +85,7 @@
for (int j = 0; j < static_cast<int>(ARRAY_SIZE(chars_to_append)); ++j) {
memmove(buffer, keyword, length);
buffer[length] = chars_to_append[j];
- i::Utf8ToUC16CharacterStream stream(buffer, length + 1);
+ i::Utf8ToUtf16CharacterStream stream(buffer, length + 1);
i::Scanner scanner(&unicode_cache);
scanner.Initialize(&stream);
CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
@@ -95,7 +95,7 @@
{
memmove(buffer, keyword, length);
buffer[length - 1] = '_';
- i::Utf8ToUC16CharacterStream stream(buffer, length);
+ i::Utf8ToUtf16CharacterStream stream(buffer, length);
i::Scanner scanner(&unicode_cache);
scanner.Initialize(&stream);
CHECK_EQ(i::Token::IDENTIFIER, scanner.Next());
@@ -255,7 +255,7 @@
uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
for (int i = 0; programs[i]; i++) {
const char* program = programs[i];
- i::Utf8ToUC16CharacterStream stream(
+ i::Utf8ToUtf16CharacterStream stream(
reinterpret_cast<const i::byte*>(program),
static_cast<unsigned>(strlen(program)));
i::CompleteParserRecorder log;
@@ -291,7 +291,7 @@
uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
for (int i = 0; programs[i]; i++) {
const char* program = programs[i];
- i::Utf8ToUC16CharacterStream stream(
+ i::Utf8ToUtf16CharacterStream stream(
reinterpret_cast<const i::byte*>(program),
static_cast<unsigned>(strlen(program)));
i::CompleteParserRecorder log;
@@ -326,8 +326,9 @@
// and then used the invalid currently scanned literal. This always
// failed in debug mode, and sometimes crashed in release mode.
- i::Utf8ToUC16CharacterStream stream(reinterpret_cast<const i::byte*>(program),
- static_cast<unsigned>(strlen(program)));
+ i::Utf8ToUtf16CharacterStream stream(
+ reinterpret_cast<const i::byte*>(program),
+ static_cast<unsigned>(strlen(program)));
i::ScriptDataImpl* data =
i::ParserApi::PreParse(&stream, NULL, false);
CHECK(data->HasError());
@@ -360,7 +361,7 @@
int first_function =
static_cast<int>(strstr(program, "function") - program);
- int first_lbrace = first_function + static_cast<int>(strlen("function () "));
+ int first_lbrace = first_function + i::StrLength("function () ");
CHECK_EQ('{', program[first_lbrace]);
i::FunctionEntry entry1 = data->GetFunctionEntry(first_lbrace);
CHECK(!entry1.is_valid());
@@ -368,7 +369,7 @@
int second_function =
static_cast<int>(strstr(program + first_lbrace, "function") - program);
int second_lbrace =
- second_function + static_cast<int>(strlen("function () "));
+ second_function + i::StrLength("function () ");
CHECK_EQ('{', program[second_lbrace]);
i::FunctionEntry entry2 = data->GetFunctionEntry(second_lbrace);
CHECK(entry2.is_valid());
@@ -392,7 +393,7 @@
uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
- i::Utf8ToUC16CharacterStream stream(
+ i::Utf8ToUtf16CharacterStream stream(
reinterpret_cast<const i::byte*>(*program),
static_cast<unsigned>(kProgramSize));
i::CompleteParserRecorder log;
@@ -449,10 +450,10 @@
i::Handle<i::String> uc16_string(
FACTORY->NewExternalStringFromTwoByte(&resource));
- i::ExternalTwoByteStringUC16CharacterStream uc16_stream(
+ i::ExternalTwoByteStringUtf16CharacterStream uc16_stream(
i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end);
- i::GenericStringUC16CharacterStream string_stream(ascii_string, start, end);
- i::Utf8ToUC16CharacterStream utf8_stream(
+ i::GenericStringUtf16CharacterStream string_stream(ascii_string, start, end);
+ i::Utf8ToUtf16CharacterStream utf8_stream(
reinterpret_cast<const i::byte*>(ascii_source), end);
utf8_stream.SeekForward(start);
@@ -575,12 +576,14 @@
char buffer[kAllUtf8CharsSizeU];
unsigned cursor = 0;
for (int i = 0; i <= kMaxUC16Char; i++) {
- cursor += unibrow::Utf8::Encode(buffer + cursor, i);
+ cursor += unibrow::Utf8::Encode(buffer + cursor,
+ i,
+ unibrow::Utf16::kNoPreviousCharacter);
}
ASSERT(cursor == kAllUtf8CharsSizeU);
- i::Utf8ToUC16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
- kAllUtf8CharsSizeU);
+ i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
+ kAllUtf8CharsSizeU);
for (int i = 0; i <= kMaxUC16Char; i++) {
CHECK_EQU(i, stream.pos());
int32_t c = stream.Advance();
@@ -610,7 +613,7 @@
#undef CHECK_EQU
-void TestStreamScanner(i::UC16CharacterStream* stream,
+void TestStreamScanner(i::Utf16CharacterStream* stream,
i::Token::Value* expected_tokens,
int skip_pos = 0, // Zero means not skipping.
int skip_to = 0) {
@@ -633,8 +636,8 @@
v8::V8::Initialize();
const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
- i::Utf8ToUC16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
- static_cast<unsigned>(strlen(str1)));
+ i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
+ static_cast<unsigned>(strlen(str1)));
i::Token::Value expectations1[] = {
i::Token::LBRACE,
i::Token::IDENTIFIER,
@@ -652,8 +655,8 @@
TestStreamScanner(&stream1, expectations1, 0, 0);
const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
- i::Utf8ToUC16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
- static_cast<unsigned>(strlen(str2)));
+ i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
+ static_cast<unsigned>(strlen(str2)));
i::Token::Value expectations2[] = {
i::Token::CASE,
i::Token::DEFAULT,
@@ -683,7 +686,7 @@
for (int i = 0; i <= 4; i++) {
expectations3[6 - i] = i::Token::ILLEGAL;
expectations3[5 - i] = i::Token::EOS;
- i::Utf8ToUC16CharacterStream stream3(
+ i::Utf8ToUtf16CharacterStream stream3(
reinterpret_cast<const i::byte*>(str3),
static_cast<unsigned>(strlen(str3)));
TestStreamScanner(&stream3, expectations3, 1, 1 + i);
@@ -692,7 +695,7 @@
void TestScanRegExp(const char* re_source, const char* expected) {
- i::Utf8ToUC16CharacterStream stream(
+ i::Utf8ToUtf16CharacterStream stream(
reinterpret_cast<const i::byte*>(re_source),
static_cast<unsigned>(strlen(re_source)));
i::Scanner scanner(i::Isolate::Current()->unicode_cache());
@@ -748,6 +751,67 @@
}
+static int Utf8LengthHelper(const char* s) {
+ int len = i::StrLength(s);
+ int character_length = len;
+ for (int i = 0; i < len; i++) {
+ unsigned char c = s[i];
+ int input_offset = 0;
+ int output_adjust = 0;
+ if (c > 0x7f) {
+ if (c < 0xc0) continue;
+ if (c >= 0xf0) {
+ if (c >= 0xf8) {
+ // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
+ // byte.
+ continue; // Handle first UTF-8 byte.
+ }
+ if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
+ // This 4 byte sequence could have been coded as a 3 byte sequence.
+ // Record a single kBadChar for the first byte and continue.
+ continue;
+ }
+ input_offset = 3;
+ // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
+ character_length -= 2;
+ } else if (c >= 0xe0) {
+ if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
+ // This 3 byte sequence could have been coded as a 2 byte sequence.
+ // Record a single kBadChar for the first byte and continue.
+ continue;
+ }
+ input_offset = 2;
+ // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
+ output_adjust = 2;
+ } else {
+ if ((c & 0x1e) == 0) {
+ // This 2 byte sequence could have been coded as a 1 byte sequence.
+ // Record a single kBadChar for the first byte and continue.
+ continue;
+ }
+ input_offset = 1;
+ // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
+ output_adjust = 1;
+ }
+ bool bad = false;
+ for (int j = 1; j <= input_offset; j++) {
+ if ((s[i + j] & 0xc0) != 0x80) {
+ // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
+ // which is a single UTF-16 code unit.
+ bad = true;
+ break;
+ }
+ }
+ if (!bad) {
+ i += input_offset;
+ character_length -= output_adjust;
+ }
+ }
+ }
+ return character_length;
+}
+
+
TEST(ScopePositions) {
// Test the parser for correctly setting the start and end positions
// of a scope. We check the scope positions of exactly one scope
@@ -835,6 +899,91 @@
{ " for ", "(let x in {})\n"
" statement;", "\n"
" more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
+ // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
+ // the preparser off in terms of byte offsets.
+ // 6 byte encoding.
+ { " 'foo\355\240\201\355\260\211';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // 4 byte encoding.
+ { " 'foo\360\220\220\212';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // 3 byte encoding of \u0fff.
+ { " 'foo\340\277\277';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Broken 6 byte encoding with missing last byte.
+ { " 'foo\355\240\201\355\211';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Broken 3 byte encoding of \u0fff with missing last byte.
+ { " 'foo\340\277';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
+ { " 'foo\340';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
+ { " 'foo\340\203\277';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
+ { " 'foo\340\201\277';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Unpaired lead surrogate.
+ { " 'foo\355\240\201';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Unpaired lead surrogate where following code point is a 3 byte sequence.
+ { " 'foo\355\240\201\340\277\277';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Unpaired lead surrogate where following code point is a 4 byte encoding
+ // of a trail surrogate.
+ { " 'foo\355\240\201\360\215\260\211';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Unpaired trail surrogate.
+ { " 'foo\355\260\211';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // 2 byte encoding of \u00ff.
+ { " 'foo\303\277';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Broken 2 byte encoding of \u00ff with missing last byte.
+ { " 'foo\303';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
+ { " 'foo\301\277';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Illegal 5 byte encoding.
+ { " 'foo\370\277\277\277\277';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Illegal 6 byte encoding.
+ { " 'foo\374\277\277\277\277\277';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Illegal 0xfe byte
+ { " 'foo\376\277\277\277\277\277\277';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ // Illegal 0xff byte
+ { " 'foo\377\277\277\277\277\277\277\277';\n"
+ " (function fun", "(a,b) { infunction; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ { " 'foo';\n"
+ " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
+ { " 'foo';\n"
+ " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
+ i::FUNCTION_SCOPE, i::CLASSIC_MODE },
{ NULL, NULL, NULL, i::EVAL_SCOPE, i::CLASSIC_MODE }
};
@@ -848,20 +997,24 @@
i::FLAG_harmony_scoping = true;
for (int i = 0; source_data[i].outer_prefix; i++) {
- int kPrefixLen = i::StrLength(source_data[i].outer_prefix);
- int kInnerLen = i::StrLength(source_data[i].inner_source);
- int kSuffixLen = i::StrLength(source_data[i].outer_suffix);
+ int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
+ int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
+ int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
+ int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
+ int kInnerByteLen = i::StrLength(source_data[i].inner_source);
+ int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
- i::Vector<char> program = i::Vector<char>::New(kProgramSize + 1);
- int length = i::OS::SNPrintF(program, "%s%s%s",
- source_data[i].outer_prefix,
- source_data[i].inner_source,
- source_data[i].outer_suffix);
- CHECK(length == kProgramSize);
+ int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
+ i::Vector<char> program = i::Vector<char>::New(kProgramByteSize + 1);
+ i::OS::SNPrintF(program, "%s%s%s",
+ source_data[i].outer_prefix,
+ source_data[i].inner_source,
+ source_data[i].outer_suffix);
// Parse program source.
i::Handle<i::String> source(
- FACTORY->NewStringFromAscii(i::CStrVector(program.start())));
+ FACTORY->NewStringFromUtf8(i::CStrVector(program.start())));
+ CHECK_EQ(source->length(), kProgramSize);
i::Handle<i::Script> script = FACTORY->NewScript(source);
i::Parser parser(script, i::kAllowLazy | i::EXTENDED_MODE, NULL, NULL);
i::CompilationInfo info(script);
@@ -894,7 +1047,7 @@
// Preparse the data.
i::CompleteParserRecorder log;
i::Scanner scanner(i::Isolate::Current()->unicode_cache());
- i::GenericStringUC16CharacterStream stream(source, 0, source->length());
+ i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
scanner.SetHarmonyScoping(harmony_scoping);
scanner.Initialize(&stream);
v8::preparser::PreParser::PreParseResult result =
diff --git a/test/mjsunit/compiler/inline-arguments.js b/test/mjsunit/compiler/inline-arguments.js
index 532fc26..b79f59c 100644
--- a/test/mjsunit/compiler/inline-arguments.js
+++ b/test/mjsunit/compiler/inline-arguments.js
@@ -27,11 +27,30 @@
// Flags: --allow-natives-syntax
-// Test inlining functions that use arguments.
-function f() { return g(1, 2, 3); }
+function A() {
+}
-function g(x, y, z) { return %_ArgumentsLength(); }
+A.prototype.X = function (a, b, c) {
+ assertTrue(this instanceof A);
+ assertEquals(1, a);
+ assertEquals(2, b);
+ assertEquals(3, c);
+};
-for (var i = 0; i < 5; ++i) f();
-%OptimizeFunctionOnNextCall(f);
-assertEquals(3, f());
+A.prototype.Y = function () {
+ this.X.apply(this, arguments);
+};
+
+A.prototype.Z = function () {
+ this.Y(1,2,3);
+};
+
+var a = new A();
+a.Z(4,5,6);
+a.Z(4,5,6);
+%OptimizeFunctionOnNextCall(a.Z);
+a.Z(4,5,6);
+A.prototype.X.apply = function (receiver, args) {
+ return Function.prototype.apply.call(this, receiver, args);
+};
+a.Z(4,5,6);
diff --git a/test/mjsunit/regress/regress-sqrt.js b/test/mjsunit/regress/regress-sqrt.js
new file mode 100644
index 0000000..f2a7e55
--- /dev/null
+++ b/test/mjsunit/regress/regress-sqrt.js
@@ -0,0 +1,47 @@
+// Copyright 2012 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.
+
+// Flags: --allow-natives-syntax
+
+// Check that Math.sqrt returns the same value regardless of being
+// optimized or not.
+
+function f(x) {
+ return Math.sqrt(x);
+}
+
+var x = 7.0506280066499245e-233;
+
+var a = f(x);
+
+f(0.1);
+f(0.2);
+%OptimizeFunctionOnNextCall(f);
+
+var b = f(x);
+
+assertEquals(a, b);
diff --git a/tools/check-static-initializers.sh b/tools/check-static-initializers.sh
new file mode 100644
index 0000000..18add3a
--- /dev/null
+++ b/tools/check-static-initializers.sh
@@ -0,0 +1,54 @@
+#!/bin/bash
+# Copyright 2012 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.
+
+# Checks that the number of compilation units having at least one static
+# initializer in d8 matches the one defined below.
+# Note that the project must be built with SCons before running this script.
+
+# Allow:
+# - _GLOBAL__I__ZN2v88internal32AtomicOps_Internalx86CPUFeaturesE
+# - _GLOBAL__I__ZN2v810LineEditor6first_E
+expected_static_init_count=2
+
+v8_root=$(readlink -f $(dirname $BASH_SOURCE)/../)
+d8="${v8_root}/d8"
+
+if [ ! -f "$d8" ]; then
+ echo "Please build the project with SCons."
+ exit 1
+fi
+
+static_inits=$(nm "$d8" | grep _GLOBAL__I | awk '{ print $NF; }')
+
+static_init_count=$(echo "$static_inits" | wc -l)
+
+if [ $static_init_count -gt $expected_static_init_count ]; then
+ echo "Too many static initializers."
+ echo "$static_inits"
+ exit 1
+fi
diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp
index b876951..764789a 100644
--- a/tools/gyp/v8.gyp
+++ b/tools/gyp/v8.gyp
@@ -40,10 +40,16 @@
'toolsets': ['target'],
}],
['v8_use_snapshot=="true"', {
- 'dependencies': ['v8_snapshot'],
+ # The dependency on v8_base should come from a transitive
+ # dependency however the Android toolchain requires libv8_base.a
+ # to appear before libv8_snapshot.a so it's listed explicitly.
+ 'dependencies': ['v8_base', 'v8_snapshot'],
},
{
- 'dependencies': ['v8_nosnapshot'],
+ # The dependency on v8_base should come from a transitive
+ # dependency however the Android toolchain requires libv8_base.a
+ # to appear before libv8_snapshot.a so it's listed explicitly.
+ 'dependencies': ['v8_base', 'v8_nosnapshot'],
}],
['component=="shared_library"', {
'type': '<(component)',
@@ -241,6 +247,7 @@
'../../src/assembler.h',
'../../src/ast.cc',
'../../src/ast.h',
+ '../../src/atomicops.h',
'../../src/atomicops_internals_x86_gcc.cc',
'../../src/bignum.cc',
'../../src/bignum.h',
@@ -353,6 +360,7 @@
'../../src/jsregexp.h',
'../../src/isolate.cc',
'../../src/isolate.h',
+ '../../src/lazy-instance.h'
'../../src/list-inl.h',
'../../src/list.h',
'../../src/lithium.cc',
@@ -383,6 +391,8 @@
'../../src/objects-visiting.h',
'../../src/objects.cc',
'../../src/objects.h',
+ '../../src/once.cc',
+ '../../src/once.h',
'../../src/parser.cc',
'../../src/parser.h',
'../../src/platform-tls-mac.h',
@@ -904,6 +914,8 @@
'../../include/v8stdint.h',
'../../src/allocation.cc',
'../../src/allocation.h',
+ '../../src/atomicops.h',
+ '../../src/atomicops_internals_x86_gcc.cc',
'../../src/bignum.cc',
'../../src/bignum.h',
'../../src/bignum-dtoa.cc',
@@ -929,6 +941,8 @@
'../../src/hashmap.h',
'../../src/list-inl.h',
'../../src/list.h',
+ '../../src/once.cc',
+ '../../src/once.h',
'../../src/preparse-data-format.h',
'../../src/preparse-data.cc',
'../../src/preparse-data.h',