blob: 308ef86805cbb90141c3fd69fc11b48f667a2d51 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000109// Assert that the given argument has a valid value for a StrictModeFlag
110// and store it in a StrictModeFlag variable with the given name.
111#define CONVERT_STRICT_MODE_ARG(name, index) \
112 ASSERT(args[index]->IsSmi()); \
113 ASSERT(args.smi_at(index) == kStrictMode || \
114 args.smi_at(index) == kNonStrictMode); \
115 StrictModeFlag name = \
116 static_cast<StrictModeFlag>(args.smi_at(index));
117
118
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000119// Assert that the given argument has a valid value for a LanguageMode
120// and store it in a LanguageMode variable with the given name.
121#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
122 ASSERT(args[index]->IsSmi()); \
123 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
124 args.smi_at(index) == STRICT_MODE || \
125 args.smi_at(index) == EXTENDED_MODE); \
126 LanguageMode name = \
127 static_cast<LanguageMode>(args.smi_at(index));
128
129
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000130MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
131 JSObject* boilerplate) {
132 StackLimitCheck check(isolate);
133 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 JSObject* copy = JSObject::cast(result);
141
142 // Deep copy local properties.
143 if (copy->HasFastProperties()) {
144 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 for (int i = 0; i < properties->length(); i++) {
146 Object* value = properties->get(i);
147 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000149 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000150 if (!maybe_result->ToObject(&result)) return maybe_result;
151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 }
154 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000155 int nof = copy->map()->inobject_properties();
156 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 Object* value = copy->InObjectPropertyAt(i);
158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000164 }
165 }
166 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 FixedArray* names = FixedArray::cast(result);
172 copy->GetLocalPropertyNames(names, 0);
173 for (int i = 0; i < names->length(); i++) {
174 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000175 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000176 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000177 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000178 // Only deep copy fields from the object literal expression.
179 // In particular, don't try to copy the length attribute of
180 // an array.
181 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000182 Object* value =
183 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000184 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000186 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000187 if (!maybe_result->ToObject(&result)) return maybe_result;
188 }
189 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000190 // Creating object copy for literals. No strict mode needed.
191 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000194 }
195 }
196 }
197
198 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000199 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000200 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000202 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000203 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000204 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000205 if (elements->map() == heap->fixed_cow_array_map()) {
206 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000207#ifdef DEBUG
208 for (int i = 0; i < elements->length(); i++) {
209 ASSERT(!elements->get(i)->IsJSObject());
210 }
211#endif
212 } else {
213 for (int i = 0; i < elements->length(); i++) {
214 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000215 ASSERT(value->IsSmi() ||
216 value->IsTheHole() ||
217 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000218 if (value->IsJSObject()) {
219 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000220 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
221 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000222 if (!maybe_result->ToObject(&result)) return maybe_result;
223 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000224 elements->set(i, result);
225 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000226 }
227 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000228 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000229 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000230 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000231 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000232 int capacity = element_dictionary->Capacity();
233 for (int i = 0; i < capacity; i++) {
234 Object* k = element_dictionary->KeyAt(i);
235 if (element_dictionary->IsKey(k)) {
236 Object* value = element_dictionary->ValueAt(i);
237 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000238 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
240 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000241 if (!maybe_result->ToObject(&result)) return maybe_result;
242 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000243 element_dictionary->ValueAtPut(i, result);
244 }
245 }
246 }
247 break;
248 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000249 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000250 UNIMPLEMENTED();
251 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000252 case EXTERNAL_PIXEL_ELEMENTS:
253 case EXTERNAL_BYTE_ELEMENTS:
254 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
255 case EXTERNAL_SHORT_ELEMENTS:
256 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
257 case EXTERNAL_INT_ELEMENTS:
258 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
259 case EXTERNAL_FLOAT_ELEMENTS:
260 case EXTERNAL_DOUBLE_ELEMENTS:
261 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000262 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000263 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000264 }
265 return copy;
266}
267
268
ager@chromium.org236ad962008-09-25 09:45:57 +0000269static Handle<Map> ComputeObjectLiteralMap(
270 Handle<Context> context,
271 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000272 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000273 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 int properties_length = constant_properties->length();
275 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000276 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000277 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000279 for (int p = 0; p != properties_length; p += 2) {
280 Object* key = constant_properties->get(p);
281 uint32_t element_index = 0;
282 if (key->IsSymbol()) {
283 number_of_symbol_keys++;
284 } else if (key->ToArrayIndex(&element_index)) {
285 // An index key does not require space in the property backing store.
286 number_of_properties--;
287 } else {
288 // Bail out as a non-symbol non-index key makes caching impossible.
289 // ASSERT to make sure that the if condition after the loop is false.
290 ASSERT(number_of_symbol_keys != number_of_properties);
291 break;
292 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000293 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000294 // If we only have symbols and array indices among keys then we can
295 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000297 if ((number_of_symbol_keys == number_of_properties) &&
298 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Handle<FixedArray> keys =
301 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000302 if (number_of_symbol_keys > 0) {
303 int index = 0;
304 for (int p = 0; p < properties_length; p += 2) {
305 Object* key = constant_properties->get(p);
306 if (key->IsSymbol()) {
307 keys->set(index++, key);
308 }
309 }
310 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000312 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000313 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000314 }
315 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000316 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000317 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000318 Handle<Map>(context->object_function()->initial_map()),
319 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000320}
321
322
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000325 Handle<FixedArray> literals,
326 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000327
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000328
329static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000331 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000332 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000333 bool should_have_fast_elements,
334 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000335 // Get the global context from the literals array. This is the
336 // context in which the function was created and we use the object
337 // function from this context to create the object literal. We do
338 // not use the object function from the current global context
339 // because this might be the object function from another context
340 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000341 Handle<Context> context =
342 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000344 // In case we have function literals, we want the object to be in
345 // slow properties mode for now. We don't go in the map cache because
346 // maps with constant functions can't be shared if the functions are
347 // not the same (which is the common case).
348 bool is_result_from_cache = false;
349 Handle<Map> map = has_function_literal
350 ? Handle<Map>(context->object_function()->initial_map())
351 : ComputeObjectLiteralMap(context,
352 constant_properties,
353 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000355 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000356
357 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000358 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 // Add the constant properties to the boilerplate.
361 int length = constant_properties->length();
362 bool should_transform =
363 !is_result_from_cache && boilerplate->HasFastProperties();
364 if (should_transform || has_function_literal) {
365 // Normalize the properties of object to avoid n^2 behavior
366 // when extending the object multiple properties. Indicate the number of
367 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000368 JSObject::NormalizeProperties(
369 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000370 }
371
372 for (int index = 0; index < length; index +=2) {
373 Handle<Object> key(constant_properties->get(index+0), isolate);
374 Handle<Object> value(constant_properties->get(index+1), isolate);
375 if (value->IsFixedArray()) {
376 // The value contains the constant_properties of a
377 // simple object or array literal.
378 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
379 value = CreateLiteralBoilerplate(isolate, literals, array);
380 if (value.is_null()) return value;
381 }
382 Handle<Object> result;
383 uint32_t element_index = 0;
384 if (key->IsSymbol()) {
385 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
386 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000387 result = JSObject::SetOwnElement(
388 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000389 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000390 Handle<String> name(String::cast(*key));
391 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000392 result = JSObject::SetLocalPropertyIgnoreAttributes(
393 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000395 } else if (key->ToArrayIndex(&element_index)) {
396 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000397 result = JSObject::SetOwnElement(
398 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000399 } else {
400 // Non-uint32 number.
401 ASSERT(key->IsNumber());
402 double num = key->Number();
403 char arr[100];
404 Vector<char> buffer(arr, ARRAY_SIZE(arr));
405 const char* str = DoubleToCString(num, buffer);
406 Handle<String> name =
407 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000408 result = JSObject::SetLocalPropertyIgnoreAttributes(
409 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 // If setting the property on the boilerplate throws an
412 // exception, the exception is converted to an empty handle in
413 // the handle based operations. In that case, we need to
414 // convert back to an exception.
415 if (result.is_null()) return result;
416 }
417
418 // Transform to fast properties if necessary. For object literals with
419 // containing function literals we defer this operation until after all
420 // computed properties have been assigned so that we can generate
421 // constant function properties.
422 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000423 JSObject::TransformToFastProperties(
424 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000425 }
426
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000427 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000428}
429
430
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000431MaybeObject* TransitionElements(Handle<Object> object,
432 ElementsKind to_kind,
433 Isolate* isolate) {
434 HandleScope scope(isolate);
435 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
436 ElementsKind from_kind =
437 Handle<JSObject>::cast(object)->map()->elements_kind();
438 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
439 Handle<Object> result = JSObject::TransitionElementsKind(
440 Handle<JSObject>::cast(object), to_kind);
441 if (result.is_null()) return isolate->ThrowIllegalOperation();
442 return *result;
443 }
444 return isolate->ThrowIllegalOperation();
445}
446
447
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000448static const int kSmiOnlyLiteralMinimumLength = 1024;
449
450
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000451Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000452 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000453 Handle<FixedArray> literals,
454 Handle<FixedArray> elements) {
455 // Create the JSArray.
456 Handle<JSFunction> constructor(
457 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000458 Handle<JSArray> object =
459 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000460
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000461 ElementsKind constant_elements_kind =
462 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
463 Handle<FixedArrayBase> constant_elements_values(
464 FixedArrayBase::cast(elements->get(1)));
465
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000466 Context* global_context = isolate->context()->global_context();
467 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
468 object->set_map(Map::cast(global_context->smi_js_array_map()));
469 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
470 object->set_map(Map::cast(global_context->double_js_array_map()));
471 } else {
472 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000473 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000474
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000475 Handle<FixedArrayBase> copied_elements_values;
476 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
477 ASSERT(FLAG_smi_only_arrays);
478 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
479 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000480 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000481 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
482 constant_elements_kind == FAST_ELEMENTS);
483 const bool is_cow =
484 (constant_elements_values->map() ==
485 isolate->heap()->fixed_cow_array_map());
486 if (is_cow) {
487 copied_elements_values = constant_elements_values;
488#if DEBUG
489 Handle<FixedArray> fixed_array_values =
490 Handle<FixedArray>::cast(copied_elements_values);
491 for (int i = 0; i < fixed_array_values->length(); i++) {
492 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
493 }
494#endif
495 } else {
496 Handle<FixedArray> fixed_array_values =
497 Handle<FixedArray>::cast(constant_elements_values);
498 Handle<FixedArray> fixed_array_values_copy =
499 isolate->factory()->CopyFixedArray(fixed_array_values);
500 copied_elements_values = fixed_array_values_copy;
501 for (int i = 0; i < fixed_array_values->length(); i++) {
502 Object* current = fixed_array_values->get(i);
503 if (current->IsFixedArray()) {
504 // The value contains the constant_properties of a
505 // simple object or array literal.
506 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
507 Handle<Object> result =
508 CreateLiteralBoilerplate(isolate, literals, fa);
509 if (result.is_null()) return result;
510 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000511 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000512 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000513 }
514 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000515 object->set_elements(*copied_elements_values);
516 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000517
518 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
519 // on or the object is larger than the threshold.
520 if (!FLAG_smi_only_arrays &&
521 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
522 if (object->GetElementsKind() != FAST_ELEMENTS) {
523 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
524 }
525 }
526
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000527 return object;
528}
529
530
531static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000532 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000533 Handle<FixedArray> literals,
534 Handle<FixedArray> array) {
535 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000536 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000537 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000538 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000539 return CreateObjectLiteralBoilerplate(isolate,
540 literals,
541 elements,
542 true,
543 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000544 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 return CreateObjectLiteralBoilerplate(isolate,
546 literals,
547 elements,
548 false,
549 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000550 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000551 return Runtime::CreateArrayLiteralBoilerplate(
552 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000553 default:
554 UNREACHABLE();
555 return Handle<Object>::null();
556 }
557}
558
559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000560RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000561 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000562 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000563 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000564 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000566 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
568 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000569
570 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 Handle<Object> boilerplate(literals->get(literals_index), isolate);
572 if (*boilerplate == isolate->heap()->undefined_value()) {
573 boilerplate = CreateObjectLiteralBoilerplate(isolate,
574 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000575 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000576 should_have_fast_elements,
577 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 if (boilerplate.is_null()) return Failure::Exception();
579 // Update the functions literal and return the boilerplate.
580 literals->set(literals_index, *boilerplate);
581 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000583}
584
585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000586RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000588 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000590 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000591 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000592 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000593 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
594 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000595
596 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 Handle<Object> boilerplate(literals->get(literals_index), isolate);
598 if (*boilerplate == isolate->heap()->undefined_value()) {
599 boilerplate = CreateObjectLiteralBoilerplate(isolate,
600 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000601 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 should_have_fast_elements,
603 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000604 if (boilerplate.is_null()) return Failure::Exception();
605 // Update the functions literal and return the boilerplate.
606 literals->set(literals_index, *boilerplate);
607 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000608 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000609}
610
611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000612RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614 ASSERT(args.length() == 3);
615 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000616 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000617 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
618
619 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 Handle<Object> boilerplate(literals->get(literals_index), isolate);
621 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000622 boilerplate =
623 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000624 if (boilerplate.is_null()) return Failure::Exception();
625 // Update the functions literal and return the boilerplate.
626 literals->set(literals_index, *boilerplate);
627 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000628 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000629}
630
631
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000632RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000633 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000634 ASSERT(args.length() == 3);
635 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000636 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000637 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
638
639 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 Handle<Object> boilerplate(literals->get(literals_index), isolate);
641 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000642 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000643 boilerplate =
644 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000645 if (boilerplate.is_null()) return Failure::Exception();
646 // Update the functions literal and return the boilerplate.
647 literals->set(literals_index, *boilerplate);
648 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000649 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000650 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000651 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000652 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000653 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000654}
655
656
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000657RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
658 ASSERT(args.length() == 2);
659 Object* handler = args[0];
660 Object* prototype = args[1];
661 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000662 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000663 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
664}
665
666
lrn@chromium.org34e60782011-09-15 07:25:40 +0000667RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
668 ASSERT(args.length() == 4);
669 Object* handler = args[0];
670 Object* call_trap = args[1];
671 Object* construct_trap = args[2];
672 Object* prototype = args[3];
673 Object* used_prototype =
674 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
675 return isolate->heap()->AllocateJSFunctionProxy(
676 handler, call_trap, construct_trap, used_prototype);
677}
678
679
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000680RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
681 ASSERT(args.length() == 1);
682 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000683 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000684}
685
686
lrn@chromium.org34e60782011-09-15 07:25:40 +0000687RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
690 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
691}
692
693
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
695 ASSERT(args.length() == 1);
696 CONVERT_CHECKED(JSProxy, proxy, args[0]);
697 return proxy->handler();
698}
699
700
lrn@chromium.org34e60782011-09-15 07:25:40 +0000701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
702 ASSERT(args.length() == 1);
703 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
704 return proxy->call_trap();
705}
706
707
708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
709 ASSERT(args.length() == 1);
710 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
711 return proxy->construct_trap();
712}
713
714
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000715RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
716 ASSERT(args.length() == 1);
717 CONVERT_CHECKED(JSProxy, proxy, args[0]);
718 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000719 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000720}
721
722
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000723RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
724 HandleScope scope(isolate);
725 ASSERT(args.length() == 1);
726 CONVERT_ARG_CHECKED(JSSet, holder, 0);
727 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
728 holder->set_table(*table);
729 return *holder;
730}
731
732
733RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
734 HandleScope scope(isolate);
735 ASSERT(args.length() == 2);
736 CONVERT_ARG_CHECKED(JSSet, holder, 0);
737 Handle<Object> key(args[1]);
738 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
739 table = ObjectHashSetAdd(table, key);
740 holder->set_table(*table);
741 return isolate->heap()->undefined_symbol();
742}
743
744
745RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
746 HandleScope scope(isolate);
747 ASSERT(args.length() == 2);
748 CONVERT_ARG_CHECKED(JSSet, holder, 0);
749 Handle<Object> key(args[1]);
750 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
751 return isolate->heap()->ToBoolean(table->Contains(*key));
752}
753
754
755RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
756 HandleScope scope(isolate);
757 ASSERT(args.length() == 2);
758 CONVERT_ARG_CHECKED(JSSet, holder, 0);
759 Handle<Object> key(args[1]);
760 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
761 table = ObjectHashSetRemove(table, key);
762 holder->set_table(*table);
763 return isolate->heap()->undefined_symbol();
764}
765
766
767RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
768 HandleScope scope(isolate);
769 ASSERT(args.length() == 1);
770 CONVERT_ARG_CHECKED(JSMap, holder, 0);
771 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
772 holder->set_table(*table);
773 return *holder;
774}
775
776
777RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
778 HandleScope scope(isolate);
779 ASSERT(args.length() == 2);
780 CONVERT_ARG_CHECKED(JSMap, holder, 0);
781 Handle<Object> key(args[1]);
782 return ObjectHashTable::cast(holder->table())->Lookup(*key);
783}
784
785
786RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
787 HandleScope scope(isolate);
788 ASSERT(args.length() == 3);
789 CONVERT_ARG_CHECKED(JSMap, holder, 0);
790 Handle<Object> key(args[1]);
791 Handle<Object> value(args[2]);
792 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
793 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
794 holder->set_table(*new_table);
795 return *value;
796}
797
798
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000799RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
800 HandleScope scope(isolate);
801 ASSERT(args.length() == 1);
802 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
803 ASSERT(weakmap->map()->inobject_properties() == 0);
804 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
805 weakmap->set_table(*table);
806 weakmap->set_next(Smi::FromInt(0));
807 return *weakmap;
808}
809
810
811RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
812 NoHandleAllocation ha;
813 ASSERT(args.length() == 2);
814 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000815 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
816 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000817}
818
819
820RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
821 HandleScope scope(isolate);
822 ASSERT(args.length() == 3);
823 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000824 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000825 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000826 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000827 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
828 weakmap->set_table(*new_table);
829 return *value;
830}
831
832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000833RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000834 NoHandleAllocation ha;
835 ASSERT(args.length() == 1);
836 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000837 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000838 return JSObject::cast(obj)->class_name();
839}
840
ager@chromium.org7c537e22008-10-16 08:43:32 +0000841
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000842RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
843 NoHandleAllocation ha;
844 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000845 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
846 Object* obj = input_obj;
847 // We don't expect access checks to be needed on JSProxy objects.
848 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000849 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000850 if (obj->IsAccessCheckNeeded() &&
851 !isolate->MayNamedAccess(JSObject::cast(obj),
852 isolate->heap()->Proto_symbol(),
853 v8::ACCESS_GET)) {
854 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
855 return isolate->heap()->undefined_value();
856 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000857 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000858 } while (obj->IsJSObject() &&
859 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000860 return obj;
861}
862
863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000864RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000865 NoHandleAllocation ha;
866 ASSERT(args.length() == 2);
867 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
868 Object* O = args[0];
869 Object* V = args[1];
870 while (true) {
871 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 if (prototype->IsNull()) return isolate->heap()->false_value();
873 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000874 V = prototype;
875 }
876}
877
878
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000879RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000881 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000882 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884}
885
886
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000887// Recursively traverses hidden prototypes if property is not found
888static void GetOwnPropertyImplementation(JSObject* obj,
889 String* name,
890 LookupResult* result) {
891 obj->LocalLookupRealNamedProperty(name, result);
892
893 if (!result->IsProperty()) {
894 Object* proto = obj->GetPrototype();
895 if (proto->IsJSObject() &&
896 JSObject::cast(proto)->map()->is_hidden_prototype())
897 GetOwnPropertyImplementation(JSObject::cast(proto),
898 name, result);
899 }
900}
901
902
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000903static bool CheckAccessException(LookupResult* result,
904 v8::AccessType access_type) {
905 if (result->type() == CALLBACKS) {
906 Object* callback = result->GetCallbackObject();
907 if (callback->IsAccessorInfo()) {
908 AccessorInfo* info = AccessorInfo::cast(callback);
909 bool can_access =
910 (access_type == v8::ACCESS_HAS &&
911 (info->all_can_read() || info->all_can_write())) ||
912 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
913 (access_type == v8::ACCESS_SET && info->all_can_write());
914 return can_access;
915 }
916 }
917
918 return false;
919}
920
921
922static bool CheckAccess(JSObject* obj,
923 String* name,
924 LookupResult* result,
925 v8::AccessType access_type) {
926 ASSERT(result->IsProperty());
927
928 JSObject* holder = result->holder();
929 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000931 while (true) {
932 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000933 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000934 // Access check callback denied the access, but some properties
935 // can have a special permissions which override callbacks descision
936 // (currently see v8::AccessControl).
937 break;
938 }
939
940 if (current == holder) {
941 return true;
942 }
943
944 current = JSObject::cast(current->GetPrototype());
945 }
946
947 // API callbacks can have per callback access exceptions.
948 switch (result->type()) {
949 case CALLBACKS: {
950 if (CheckAccessException(result, access_type)) {
951 return true;
952 }
953 break;
954 }
955 case INTERCEPTOR: {
956 // If the object has an interceptor, try real named properties.
957 // Overwrite the result to fetch the correct property later.
958 holder->LookupRealNamedProperty(name, result);
959 if (result->IsProperty()) {
960 if (CheckAccessException(result, access_type)) {
961 return true;
962 }
963 }
964 break;
965 }
966 default:
967 break;
968 }
969
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000970 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000971 return false;
972}
973
974
975// TODO(1095): we should traverse hidden prototype hierachy as well.
976static bool CheckElementAccess(JSObject* obj,
977 uint32_t index,
978 v8::AccessType access_type) {
979 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000981 return false;
982 }
983
984 return true;
985}
986
987
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000988// Enumerator used as indices into the array returned from GetOwnProperty
989enum PropertyDescriptorIndices {
990 IS_ACCESSOR_INDEX,
991 VALUE_INDEX,
992 GETTER_INDEX,
993 SETTER_INDEX,
994 WRITABLE_INDEX,
995 ENUMERABLE_INDEX,
996 CONFIGURABLE_INDEX,
997 DESCRIPTOR_SIZE
998};
999
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001000// Returns an array with the property description:
1001// if args[1] is not a property on args[0]
1002// returns undefined
1003// if args[1] is a data property on args[0]
1004// [false, value, Writeable, Enumerable, Configurable]
1005// if args[1] is an accessor on args[0]
1006// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001007RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001008 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001009 Heap* heap = isolate->heap();
1010 HandleScope scope(isolate);
1011 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1012 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001013 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001014 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1015 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001016
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001017 // This could be an element.
1018 uint32_t index;
1019 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001020 switch (obj->HasLocalElement(index)) {
1021 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001022 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001023
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001024 case JSObject::STRING_CHARACTER_ELEMENT: {
1025 // Special handling of string objects according to ECMAScript 5
1026 // 15.5.5.2. Note that this might be a string object with elements
1027 // other than the actual string value. This is covered by the
1028 // subsequent cases.
1029 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1030 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001031 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001032
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001034 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001035 elms->set(WRITABLE_INDEX, heap->false_value());
1036 elms->set(ENUMERABLE_INDEX, heap->false_value());
1037 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001038 return *desc;
1039 }
1040
1041 case JSObject::INTERCEPTED_ELEMENT:
1042 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001043 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001044 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001045 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001046 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001047 elms->set(WRITABLE_INDEX, heap->true_value());
1048 elms->set(ENUMERABLE_INDEX, heap->true_value());
1049 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001050 return *desc;
1051 }
1052
1053 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001054 Handle<JSObject> holder = obj;
1055 if (obj->IsJSGlobalProxy()) {
1056 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001057 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001058 ASSERT(proto->IsJSGlobalObject());
1059 holder = Handle<JSObject>(JSObject::cast(proto));
1060 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001061 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001062 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001063 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001064 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001065 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001066 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001067 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001068 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001069 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001070 PropertyDetails details = dictionary->DetailsAt(entry);
1071 switch (details.type()) {
1072 case CALLBACKS: {
1073 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001074 AccessorPair* accessors =
1075 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001077 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001078 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001079 }
1080 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001081 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001082 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001083 break;
1084 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001085 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001086 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001087 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001088 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001089 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001090 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001091 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001092 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001093 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001094 default:
1095 UNREACHABLE();
1096 break;
1097 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1099 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001100 return *desc;
1101 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001102 }
1103 }
1104
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001105 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001106 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001107
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001108 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001109 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001110 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001111
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001112 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001114 }
1115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001116 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1117 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001118
1119 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001120 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001121
1122 if (is_js_accessor) {
1123 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001124 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001125
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001126 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001127 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001128 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001129 }
1130 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001131 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001132 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001133 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001134 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1135 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001136
1137 PropertyAttributes attrs;
1138 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001139 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001140 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1141 if (!maybe_value->ToObject(&value)) return maybe_value;
1142 }
1143 elms->set(VALUE_INDEX, value);
1144 }
1145
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001146 return *desc;
1147}
1148
1149
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001150RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001151 ASSERT(args.length() == 1);
1152 CONVERT_CHECKED(JSObject, obj, args[0]);
1153 return obj->PreventExtensions();
1154}
1155
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001156
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001157RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001158 ASSERT(args.length() == 1);
1159 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001160 if (obj->IsJSGlobalProxy()) {
1161 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001162 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001163 ASSERT(proto->IsJSGlobalObject());
1164 obj = JSObject::cast(proto);
1165 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001166 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001167}
1168
1169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001170RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001171 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001173 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1174 CONVERT_ARG_CHECKED(String, pattern, 1);
1175 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001176 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1177 if (result.is_null()) return Failure::Exception();
1178 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179}
1180
1181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001182RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001183 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001185 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001186 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001187}
1188
1189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001190RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001191 ASSERT(args.length() == 1);
1192 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001193 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195}
1196
1197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001198RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001199 ASSERT(args.length() == 2);
1200 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001201 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001202 int index = field->value();
1203 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1204 InstanceType type = templ->map()->instance_type();
1205 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1206 type == OBJECT_TEMPLATE_INFO_TYPE);
1207 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001208 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001209 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1210 } else {
1211 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1212 }
1213 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214}
1215
1216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001217RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001218 ASSERT(args.length() == 1);
1219 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001220 Map* old_map = object->map();
1221 bool needs_access_checks = old_map->is_access_check_needed();
1222 if (needs_access_checks) {
1223 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001224 Object* new_map;
1225 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1226 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1227 }
ager@chromium.org32912102009-01-16 10:38:43 +00001228
1229 Map::cast(new_map)->set_is_access_check_needed(false);
1230 object->set_map(Map::cast(new_map));
1231 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001232 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001233}
1234
1235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001236RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001237 ASSERT(args.length() == 1);
1238 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001239 Map* old_map = object->map();
1240 if (!old_map->is_access_check_needed()) {
1241 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001242 Object* new_map;
1243 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1244 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1245 }
ager@chromium.org32912102009-01-16 10:38:43 +00001246
1247 Map::cast(new_map)->set_is_access_check_needed(true);
1248 object->set_map(Map::cast(new_map));
1249 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001250 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001251}
1252
1253
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001254static Failure* ThrowRedeclarationError(Isolate* isolate,
1255 const char* type,
1256 Handle<String> name) {
1257 HandleScope scope(isolate);
1258 Handle<Object> type_handle =
1259 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260 Handle<Object> args[2] = { type_handle, name };
1261 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001262 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1263 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264}
1265
1266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001267RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001268 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001269 HandleScope scope(isolate);
1270 Handle<GlobalObject> global = Handle<GlobalObject>(
1271 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001272
ager@chromium.org3811b432009-10-28 14:53:37 +00001273 Handle<Context> context = args.at<Context>(0);
1274 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001275 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 // Traverse the name/value pairs and set the properties.
1278 int length = pairs->length();
1279 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001280 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001282 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283
1284 // We have to declare a global const property. To capture we only
1285 // assign to it when evaluating the assignment for "const x =
1286 // <expr>" the initial value is the hole.
1287 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001288 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001289 if (value->IsUndefined() || is_const_property) {
1290 // Lookup the property in the global object, and don't set the
1291 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001292 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 global->Lookup(*name, &lookup);
1294 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001295 // We found an existing property. Unless it was an interceptor
1296 // that claims the property is absent, skip this declaration.
1297 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298 continue;
1299 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1301 if (attributes != ABSENT) {
1302 continue;
1303 }
1304 // Fall-through and introduce the absent property by using
1305 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001306 }
1307 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001308 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001309 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001310 Handle<SharedFunctionInfo> shared =
1311 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001313 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1314 context,
1315 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 value = function;
1317 }
1318
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001319 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320 global->LocalLookup(*name, &lookup);
1321
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001322 // Compute the property attributes. According to ECMA-262, section
1323 // 13, page 71, the property must be read-only and
1324 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1325 // property as read-only, so we don't either.
1326 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001327 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001328 attr |= DONT_DELETE;
1329 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001330 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001331 if (is_const_property || (is_native && is_function_declaration)) {
1332 attr |= READ_ONLY;
1333 }
1334
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001335 // Safari does not allow the invocation of callback setters for
1336 // function declarations. To mimic this behavior, we do not allow
1337 // the invocation of setters for function values. This makes a
1338 // difference for global functions with the same names as event
1339 // handlers such as "function onload() {}". Firefox does call the
1340 // onload setter in those case and Safari does not. We follow
1341 // Safari for compatibility.
1342 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001343 // Do not change DONT_DELETE to false from true.
1344 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001345 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001346 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001347 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1348
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001349 RETURN_IF_EMPTY_HANDLE(
1350 isolate,
1351 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1352 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001354 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1355 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1356 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001357 RETURN_IF_EMPTY_HANDLE(
1358 isolate,
1359 JSReceiver::SetProperty(global, name, value,
1360 static_cast<PropertyAttributes>(attr),
1361 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001362 }
1363 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001364
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001365 ASSERT(!isolate->has_pending_exception());
1366 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367}
1368
1369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001370RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001371 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001372 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001373
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001374 // Declarations are always made in a function or global context. In the
1375 // case of eval code, the context passed is the context of the caller,
1376 // which may be some nested context and not the declaration context.
1377 RUNTIME_ASSERT(args[0]->IsContext());
1378 Handle<Context> context(Context::cast(args[0])->declaration_context());
1379
ager@chromium.org7c537e22008-10-16 08:43:32 +00001380 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001381 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001382 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001383 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385 int index;
1386 PropertyAttributes attributes;
1387 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001388 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001389 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001390 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001391
1392 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001393 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001394 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1395 // Functions are not read-only.
1396 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1397 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001398 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 }
1400
1401 // Initialize it if necessary.
1402 if (*initial_value != NULL) {
1403 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001404 ASSERT(holder.is_identical_to(context));
1405 if (((attributes & READ_ONLY) == 0) ||
1406 context->get(index)->IsTheHole()) {
1407 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001408 }
1409 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001410 // Slow case: The property is in the context extension object of a
1411 // function context or the global object of a global context.
1412 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001413 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001414 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001415 JSReceiver::SetProperty(object, name, initial_value, mode,
1416 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 }
1418 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001421 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001422 // "declared" in the function context's extension context or as a
1423 // property of the the global object.
1424 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001425 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001426 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001427 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001428 // Context extension objects are allocated lazily.
1429 ASSERT(context->IsFunctionContext());
1430 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001431 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001432 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001433 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001434 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435
ager@chromium.org7c537e22008-10-16 08:43:32 +00001436 // Declare the property by setting it to the initial value if provided,
1437 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1438 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001439 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001440 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001441 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001442 // Declaring a const context slot is a conflicting declaration if
1443 // there is a callback with that name in a prototype. It is
1444 // allowed to introduce const variables in
1445 // JSContextExtensionObjects. They are treated specially in
1446 // SetProperty and no setters are invoked for those since they are
1447 // not real JSObjects.
1448 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001449 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001450 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001451 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001452 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001453 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001454 }
1455 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001456 RETURN_IF_EMPTY_HANDLE(
1457 isolate,
1458 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001459 }
1460
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001461 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001462}
1463
1464
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001465RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001467 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001468 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001469 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470
1471 // Determine if we need to assign to the variable if it already
1472 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001473 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1474 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001475
1476 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001477 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001478 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001479 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1480 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1481 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001482
1483 // According to ECMA-262, section 12.2, page 62, the property must
1484 // not be deletable.
1485 PropertyAttributes attributes = DONT_DELETE;
1486
1487 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001488 // there, there is a property with this name in the prototype chain.
1489 // We follow Safari and Firefox behavior and only set the property
1490 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001491 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001492 // Note that objects can have hidden prototypes, so we need to traverse
1493 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001494 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001495 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001496 while (object->IsJSObject() &&
1497 JSObject::cast(object)->map()->is_hidden_prototype()) {
1498 JSObject* raw_holder = JSObject::cast(object);
1499 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001500 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 HandleScope handle_scope(isolate);
1502 Handle<JSObject> holder(raw_holder);
1503 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1504 // Update the raw pointer in case it's changed due to GC.
1505 raw_holder = *holder;
1506 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1507 // Found an interceptor that's not read only.
1508 if (assign) {
1509 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001510 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001511 } else {
1512 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001513 }
1514 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001515 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001516 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517 }
1518
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001519 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001520 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001521 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001522 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001523 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001524 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001525}
1526
1527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001528RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529 // All constants are declared with an initial value. The name
1530 // of the constant is the first argument and the initial value
1531 // is the second.
1532 RUNTIME_ASSERT(args.length() == 2);
1533 CONVERT_ARG_CHECKED(String, name, 0);
1534 Handle<Object> value = args.at<Object>(1);
1535
1536 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001537 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001538
1539 // According to ECMA-262, section 12.2, page 62, the property must
1540 // not be deletable. Since it's a const, it must be READ_ONLY too.
1541 PropertyAttributes attributes =
1542 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1543
1544 // Lookup the property locally in the global object. If it isn't
1545 // there, we add the property and take special precautions to always
1546 // add it as a local property even in case of callbacks in the
1547 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001548 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001549 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550 global->LocalLookup(*name, &lookup);
1551 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001552 return global->SetLocalPropertyIgnoreAttributes(*name,
1553 *value,
1554 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 }
1556
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001557 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001558 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001559 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001560 HandleScope handle_scope(isolate);
1561 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001563 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 // property through an interceptor and only do it if it's
1565 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001566 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001567 RETURN_IF_EMPTY_HANDLE(
1568 isolate,
1569 JSReceiver::SetProperty(global, name, value, attributes,
1570 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571 return *value;
1572 }
1573
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001574 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001575 // constant. For now, we determine this by checking if the
1576 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001577 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578 PropertyType type = lookup.type();
1579 if (type == FIELD) {
1580 FixedArray* properties = global->properties();
1581 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001582 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583 properties->set(index, *value);
1584 }
1585 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001586 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1587 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001588 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589 }
1590 } else {
1591 // Ignore re-initialization of constants that have already been
1592 // assigned a function value.
1593 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1594 }
1595
1596 // Use the set value as the result of the operation.
1597 return *value;
1598}
1599
1600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001601RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001602 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603 ASSERT(args.length() == 3);
1604
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001605 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001606 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001608 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001609 RUNTIME_ASSERT(args[1]->IsContext());
1610 Handle<Context> context(Context::cast(args[1])->declaration_context());
1611
1612 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613
1614 int index;
1615 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001616 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001617 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001618 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001619 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001622 ASSERT(holder->IsContext());
1623 // Property was found in a context. Perform the assignment if we
1624 // found some non-constant or an uninitialized constant.
1625 Handle<Context> context = Handle<Context>::cast(holder);
1626 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1627 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628 }
1629 return *value;
1630 }
1631
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001632 // The property could not be found, we introduce it as a property of the
1633 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001634 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001635 Handle<JSObject> global = Handle<JSObject>(
1636 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001637 // Strict mode not needed (const disallowed in strict mode).
1638 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001639 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001640 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001641 return *value;
1642 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001644 // The property was present in some function's context extension object,
1645 // as a property on the subject of a with, or as a property of the global
1646 // object.
1647 //
1648 // In most situations, eval-introduced consts should still be present in
1649 // the context extension object. However, because declaration and
1650 // initialization are separate, the property might have been deleted
1651 // before we reach the initialization point.
1652 //
1653 // Example:
1654 //
1655 // function f() { eval("delete x; const x;"); }
1656 //
1657 // In that case, the initialization behaves like a normal assignment.
1658 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001659
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001660 if (*object == context->extension()) {
1661 // This is the property that was introduced by the const declaration.
1662 // Set it if it hasn't been set before. NOTE: We cannot use
1663 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001664 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001665 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001666 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001667 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1668
1669 PropertyType type = lookup.type();
1670 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001671 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001672 int index = lookup.GetFieldIndex();
1673 if (properties->get(index)->IsTheHole()) {
1674 properties->set(index, *value);
1675 }
1676 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001677 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1678 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001679 }
1680 } else {
1681 // We should not reach here. Any real, named property should be
1682 // either a field or a dictionary slot.
1683 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001684 }
1685 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001686 // The property was found on some other object. Set it if it is not a
1687 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001688 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001689 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001690 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001691 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001692 JSReceiver::SetProperty(object, name, value, attributes,
1693 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001694 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001695 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001696
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001697 return *value;
1698}
1699
1700
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001701RUNTIME_FUNCTION(MaybeObject*,
1702 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001703 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001704 ASSERT(args.length() == 2);
1705 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001706 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001707 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001708 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001709 }
1710 return *object;
1711}
1712
1713
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001714RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001715 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001716 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001717 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1718 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001719 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001720 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001721 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001722 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001723 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001724 RUNTIME_ASSERT(index >= 0);
1725 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001727 Handle<Object> result = RegExpImpl::Exec(regexp,
1728 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001729 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001730 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001731 if (result.is_null()) return Failure::Exception();
1732 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733}
1734
1735
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001736RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001737 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001738 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001739 if (elements_count < 0 ||
1740 elements_count > FixedArray::kMaxLength ||
1741 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001742 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001743 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001744 Object* new_object;
1745 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001747 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1748 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001749 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001750 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1751 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001752 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1753 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001754 {
1755 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001757 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001758 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001759 }
1760 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001761 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001762 array->set_elements(elements);
1763 array->set_length(Smi::FromInt(elements_count));
1764 // Write in-object properties after the length of the array.
1765 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1766 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1767 return array;
1768}
1769
1770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001771RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001772 AssertNoAllocation no_alloc;
1773 ASSERT(args.length() == 5);
1774 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1775 CONVERT_CHECKED(String, source, args[1]);
1776
1777 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001778 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001779
1780 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001781 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001782
1783 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001784 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001785
1786 Map* map = regexp->map();
1787 Object* constructor = map->constructor();
1788 if (constructor->IsJSFunction() &&
1789 JSFunction::cast(constructor)->initial_map() == map) {
1790 // If we still have the original map, set in-object properties directly.
1791 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001792 // Both true and false are immovable immortal objects so no need for write
1793 // barrier.
1794 regexp->InObjectPropertyAtPut(
1795 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1796 regexp->InObjectPropertyAtPut(
1797 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1798 regexp->InObjectPropertyAtPut(
1799 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001800 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1801 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001802 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001803 return regexp;
1804 }
1805
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001806 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001807 PropertyAttributes final =
1808 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1809 PropertyAttributes writable =
1810 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001812 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001814 source,
1815 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001816 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001818 global,
1819 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001820 ASSERT(!result->IsFailure());
1821 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001822 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001823 ignoreCase,
1824 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001825 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001827 multiline,
1828 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001829 ASSERT(!result->IsFailure());
1830 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001832 Smi::FromInt(0),
1833 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001834 ASSERT(!result->IsFailure());
1835 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001836 return regexp;
1837}
1838
1839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001840RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001841 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001842 ASSERT(args.length() == 1);
1843 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1844 // This is necessary to enable fast checks for absence of elements
1845 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001846 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001847 return Smi::FromInt(0);
1848}
1849
1850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001851static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1852 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001853 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001854 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1856 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1857 Handle<JSFunction> optimized =
1858 isolate->factory()->NewFunction(key,
1859 JS_OBJECT_TYPE,
1860 JSObject::kHeaderSize,
1861 code,
1862 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001863 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001864 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001865 return optimized;
1866}
1867
1868
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001869RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001870 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001871 ASSERT(args.length() == 1);
1872 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1873
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001874 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1875 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1876 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1877 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1878 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1879 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1880 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001881
1882 return *holder;
1883}
1884
1885
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001886RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001887 ASSERT(args.length() == 1);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001888 CONVERT_CHECKED(JSReceiver, callable, args[0]);
1889
1890 if (!callable->IsJSFunction()) {
1891 HandleScope scope(isolate);
1892 bool threw = false;
1893 Handle<Object> delegate =
1894 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1895 if (threw) return Failure::Exception();
1896 callable = JSFunction::cast(*delegate);
1897 }
1898 JSFunction* function = JSFunction::cast(callable);
1899
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001900 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001901 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001902 return isolate->heap()->undefined_value();
1903 }
1904 // Returns undefined for strict or native functions, or
1905 // the associated global receiver for "normal" functions.
1906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001907 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001908 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001909 return global_context->global()->global_receiver();
1910}
1911
1912
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001913RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001914 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 ASSERT(args.length() == 4);
1916 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001917 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 Handle<String> pattern = args.at<String>(2);
1919 Handle<String> flags = args.at<String>(3);
1920
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001921 // Get the RegExp function from the context in the literals array.
1922 // This is the RegExp function from the context in which the
1923 // function was created. We do not use the RegExp function from the
1924 // current global context because this might be the RegExp function
1925 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001926 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001927 Handle<JSFunction>(
1928 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929 // Compute the regular expression literal.
1930 bool has_pending_exception;
1931 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001932 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1933 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001935 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001936 return Failure::Exception();
1937 }
1938 literals->set(index, *regexp);
1939 return *regexp;
1940}
1941
1942
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001943RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001944 NoHandleAllocation ha;
1945 ASSERT(args.length() == 1);
1946
1947 CONVERT_CHECKED(JSFunction, f, args[0]);
1948 return f->shared()->name();
1949}
1950
1951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001952RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001953 NoHandleAllocation ha;
1954 ASSERT(args.length() == 2);
1955
1956 CONVERT_CHECKED(JSFunction, f, args[0]);
1957 CONVERT_CHECKED(String, name, args[1]);
1958 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001959 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001960}
1961
1962
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001963RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1964 NoHandleAllocation ha;
1965 ASSERT(args.length() == 1);
1966 CONVERT_CHECKED(JSFunction, f, args[0]);
1967 return isolate->heap()->ToBoolean(
1968 f->shared()->name_should_print_as_anonymous());
1969}
1970
1971
1972RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1973 NoHandleAllocation ha;
1974 ASSERT(args.length() == 1);
1975 CONVERT_CHECKED(JSFunction, f, args[0]);
1976 f->shared()->set_name_should_print_as_anonymous(true);
1977 return isolate->heap()->undefined_value();
1978}
1979
1980
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001981RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001982 NoHandleAllocation ha;
1983 ASSERT(args.length() == 1);
1984
1985 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001986 Object* obj = f->RemovePrototype();
1987 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001988
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001989 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001990}
1991
1992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001993RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001994 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995 ASSERT(args.length() == 1);
1996
1997 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001998 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1999 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002000
2001 return *GetScriptWrapper(Handle<Script>::cast(script));
2002}
2003
2004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002005RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002006 NoHandleAllocation ha;
2007 ASSERT(args.length() == 1);
2008
2009 CONVERT_CHECKED(JSFunction, f, args[0]);
2010 return f->shared()->GetSourceCode();
2011}
2012
2013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002014RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002015 NoHandleAllocation ha;
2016 ASSERT(args.length() == 1);
2017
2018 CONVERT_CHECKED(JSFunction, fun, args[0]);
2019 int pos = fun->shared()->start_position();
2020 return Smi::FromInt(pos);
2021}
2022
2023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002024RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002025 ASSERT(args.length() == 2);
2026
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002027 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002028 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2029
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002030 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2031
2032 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002033 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002034}
2035
2036
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002037RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002038 NoHandleAllocation ha;
2039 ASSERT(args.length() == 2);
2040
2041 CONVERT_CHECKED(JSFunction, fun, args[0]);
2042 CONVERT_CHECKED(String, name, args[1]);
2043 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002044 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002045}
2046
2047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002048RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049 NoHandleAllocation ha;
2050 ASSERT(args.length() == 2);
2051
2052 CONVERT_CHECKED(JSFunction, fun, args[0]);
2053 CONVERT_CHECKED(Smi, length, args[1]);
2054 fun->shared()->set_length(length->value());
2055 return length;
2056}
2057
2058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002059RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002060 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002061 ASSERT(args.length() == 2);
2062
2063 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002064 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002065 Object* obj;
2066 { MaybeObject* maybe_obj =
2067 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2068 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2069 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002070 return args[0]; // return TOS
2071}
2072
2073
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002074RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2075 NoHandleAllocation ha;
2076 RUNTIME_ASSERT(args.length() == 1);
2077 CONVERT_CHECKED(JSFunction, function, args[0]);
2078
2079 MaybeObject* maybe_name =
2080 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2081 String* name;
2082 if (!maybe_name->To(&name)) return maybe_name;
2083
2084 if (function->HasFastProperties()) {
2085 // Construct a new field descriptor with updated attributes.
2086 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2087 int index = instance_desc->Search(name);
2088 ASSERT(index != DescriptorArray::kNotFound);
2089 PropertyDetails details(instance_desc->GetDetails(index));
2090 CallbacksDescriptor new_desc(name,
2091 instance_desc->GetValue(index),
2092 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2093 details.index());
2094 // Construct a new field descriptors array containing the new descriptor.
2095 Object* descriptors_unchecked;
2096 { MaybeObject* maybe_descriptors_unchecked =
2097 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2098 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2099 return maybe_descriptors_unchecked;
2100 }
2101 }
2102 DescriptorArray* new_descriptors =
2103 DescriptorArray::cast(descriptors_unchecked);
2104 // Create a new map featuring the new field descriptors array.
2105 Object* map_unchecked;
2106 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2107 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2108 return maybe_map_unchecked;
2109 }
2110 }
2111 Map* new_map = Map::cast(map_unchecked);
2112 new_map->set_instance_descriptors(new_descriptors);
2113 function->set_map(new_map);
2114 } else { // Dictionary properties.
2115 // Directly manipulate the property details.
2116 int entry = function->property_dictionary()->FindEntry(name);
2117 ASSERT(entry != StringDictionary::kNotFound);
2118 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2119 PropertyDetails new_details(
2120 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2121 details.type(),
2122 details.index());
2123 function->property_dictionary()->DetailsAtPut(entry, new_details);
2124 }
2125 return function;
2126}
2127
2128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002129RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002130 NoHandleAllocation ha;
2131 ASSERT(args.length() == 1);
2132
2133 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002134 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002135}
2136
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002137
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002138RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002139 NoHandleAllocation ha;
2140 ASSERT(args.length() == 1);
2141
2142 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002143 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002144}
2145
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002147RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002148 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002149 ASSERT(args.length() == 2);
2150
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002151 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002152 Handle<Object> code = args.at<Object>(1);
2153
2154 Handle<Context> context(target->context());
2155
2156 if (!code->IsNull()) {
2157 RUNTIME_ASSERT(code->IsJSFunction());
2158 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002159 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002160
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002161 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002162 return Failure::Exception();
2163 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002164 // Since we don't store the source for this we should never
2165 // optimize this.
2166 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002167 // Set the code, scope info, formal parameter count,
2168 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002169 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002170 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002171 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002172 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002173 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002174 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002175 // Set the source code of the target function to undefined.
2176 // SetCode is only used for built-in constructors like String,
2177 // Array, and Object, and some web code
2178 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002179 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002180 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002181 // Clear the optimization hints related to the compiled code as these are no
2182 // longer valid when the code is overwritten.
2183 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 context = Handle<Context>(fun->context());
2185
2186 // Make sure we get a fresh copy of the literal vector to avoid
2187 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002188 int number_of_literals = fun->NumberOfLiterals();
2189 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002190 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002191 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002192 // Insert the object, regexp and array functions in the literals
2193 // array prefix. These are the functions that will be used when
2194 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002195 literals->set(JSFunction::kLiteralGlobalContextIndex,
2196 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002198 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002199 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002200
2201 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2202 isolate->logger()->LogExistingFunction(
2203 shared, Handle<Code>(shared->code()));
2204 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002205 }
2206
2207 target->set_context(*context);
2208 return *target;
2209}
2210
2211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002212RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002213 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002214 ASSERT(args.length() == 2);
2215 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002216 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002217 RUNTIME_ASSERT(num >= 0);
2218 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002219 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002220}
2221
2222
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002223MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2224 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002225 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002226 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002227 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002228 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002229 }
2230 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002231 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002232}
2233
2234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002235RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002236 NoHandleAllocation ha;
2237 ASSERT(args.length() == 2);
2238
2239 CONVERT_CHECKED(String, subject, args[0]);
2240 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002241 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002242
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002243 uint32_t i = 0;
2244 if (index->IsSmi()) {
2245 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002246 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002247 i = value;
2248 } else {
2249 ASSERT(index->IsHeapNumber());
2250 double value = HeapNumber::cast(index)->value();
2251 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002252 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002253
2254 // Flatten the string. If someone wants to get a char at an index
2255 // in a cons string, it is likely that more indices will be
2256 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002257 Object* flat;
2258 { MaybeObject* maybe_flat = subject->TryFlatten();
2259 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2260 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002261 subject = String::cast(flat);
2262
2263 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002264 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002265 }
2266
2267 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002268}
2269
2270
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002271RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002272 NoHandleAllocation ha;
2273 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002274 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002275}
2276
lrn@chromium.org25156de2010-04-06 13:10:27 +00002277
2278class FixedArrayBuilder {
2279 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002280 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2281 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002282 length_(0),
2283 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002284 // Require a non-zero initial size. Ensures that doubling the size to
2285 // extend the array will work.
2286 ASSERT(initial_capacity > 0);
2287 }
2288
2289 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2290 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002291 length_(0),
2292 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002293 // Require a non-zero initial size. Ensures that doubling the size to
2294 // extend the array will work.
2295 ASSERT(backing_store->length() > 0);
2296 }
2297
2298 bool HasCapacity(int elements) {
2299 int length = array_->length();
2300 int required_length = length_ + elements;
2301 return (length >= required_length);
2302 }
2303
2304 void EnsureCapacity(int elements) {
2305 int length = array_->length();
2306 int required_length = length_ + elements;
2307 if (length < required_length) {
2308 int new_length = length;
2309 do {
2310 new_length *= 2;
2311 } while (new_length < required_length);
2312 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002313 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002314 array_->CopyTo(0, *extended_array, 0, length_);
2315 array_ = extended_array;
2316 }
2317 }
2318
2319 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002320 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002321 ASSERT(length_ < capacity());
2322 array_->set(length_, value);
2323 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002324 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002325 }
2326
2327 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002328 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 ASSERT(length_ < capacity());
2330 array_->set(length_, value);
2331 length_++;
2332 }
2333
2334 Handle<FixedArray> array() {
2335 return array_;
2336 }
2337
2338 int length() {
2339 return length_;
2340 }
2341
2342 int capacity() {
2343 return array_->length();
2344 }
2345
2346 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002347 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002348 result_array->set_length(Smi::FromInt(length_));
2349 return result_array;
2350 }
2351
2352 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002353 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002354 target_array->set_length(Smi::FromInt(length_));
2355 return target_array;
2356 }
2357
2358 private:
2359 Handle<FixedArray> array_;
2360 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002361 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002362};
2363
2364
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002365// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002366const int kStringBuilderConcatHelperLengthBits = 11;
2367const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002368
2369template <typename schar>
2370static inline void StringBuilderConcatHelper(String*,
2371 schar*,
2372 FixedArray*,
2373 int);
2374
lrn@chromium.org25156de2010-04-06 13:10:27 +00002375typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2376 StringBuilderSubstringLength;
2377typedef BitField<int,
2378 kStringBuilderConcatHelperLengthBits,
2379 kStringBuilderConcatHelperPositionBits>
2380 StringBuilderSubstringPosition;
2381
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002382
2383class ReplacementStringBuilder {
2384 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002385 ReplacementStringBuilder(Heap* heap,
2386 Handle<String> subject,
2387 int estimated_part_count)
2388 : heap_(heap),
2389 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002390 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002391 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002392 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002393 // Require a non-zero initial size. Ensures that doubling the size to
2394 // extend the array will work.
2395 ASSERT(estimated_part_count > 0);
2396 }
2397
lrn@chromium.org25156de2010-04-06 13:10:27 +00002398 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2399 int from,
2400 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002401 ASSERT(from >= 0);
2402 int length = to - from;
2403 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002404 if (StringBuilderSubstringLength::is_valid(length) &&
2405 StringBuilderSubstringPosition::is_valid(from)) {
2406 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2407 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002408 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002409 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002410 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002411 builder->Add(Smi::FromInt(-length));
2412 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002413 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002414 }
2415
2416
2417 void EnsureCapacity(int elements) {
2418 array_builder_.EnsureCapacity(elements);
2419 }
2420
2421
2422 void AddSubjectSlice(int from, int to) {
2423 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002424 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002425 }
2426
2427
2428 void AddString(Handle<String> string) {
2429 int length = string->length();
2430 ASSERT(length > 0);
2431 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002432 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002433 is_ascii_ = false;
2434 }
2435 IncrementCharacterCount(length);
2436 }
2437
2438
2439 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002440 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002441 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002442 }
2443
2444 Handle<String> joined_string;
2445 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002446 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002447 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 char* char_buffer = seq->GetChars();
2449 StringBuilderConcatHelper(*subject_,
2450 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002451 *array_builder_.array(),
2452 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002453 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002454 } else {
2455 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002456 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002457 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002458 uc16* char_buffer = seq->GetChars();
2459 StringBuilderConcatHelper(*subject_,
2460 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002461 *array_builder_.array(),
2462 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002463 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002464 }
2465 return joined_string;
2466 }
2467
2468
2469 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002470 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002471 V8::FatalProcessOutOfMemory("String.replace result too large.");
2472 }
2473 character_count_ += by;
2474 }
2475
lrn@chromium.org25156de2010-04-06 13:10:27 +00002476 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002477 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002478 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002479
lrn@chromium.org25156de2010-04-06 13:10:27 +00002480 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002481 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2482 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002483 }
2484
2485
ager@chromium.org04921a82011-06-27 13:21:41 +00002486 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2487 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002488 }
2489
2490
2491 void AddElement(Object* element) {
2492 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002493 ASSERT(array_builder_.capacity() > array_builder_.length());
2494 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002495 }
2496
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002497 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002498 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002499 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002500 int character_count_;
2501 bool is_ascii_;
2502};
2503
2504
2505class CompiledReplacement {
2506 public:
2507 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002508 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002509
2510 void Compile(Handle<String> replacement,
2511 int capture_count,
2512 int subject_length);
2513
2514 void Apply(ReplacementStringBuilder* builder,
2515 int match_from,
2516 int match_to,
2517 Handle<JSArray> last_match_info);
2518
2519 // Number of distinct parts of the replacement pattern.
2520 int parts() {
2521 return parts_.length();
2522 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002523
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002524 bool simple_hint() {
2525 return simple_hint_;
2526 }
2527
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002528 private:
2529 enum PartType {
2530 SUBJECT_PREFIX = 1,
2531 SUBJECT_SUFFIX,
2532 SUBJECT_CAPTURE,
2533 REPLACEMENT_SUBSTRING,
2534 REPLACEMENT_STRING,
2535
2536 NUMBER_OF_PART_TYPES
2537 };
2538
2539 struct ReplacementPart {
2540 static inline ReplacementPart SubjectMatch() {
2541 return ReplacementPart(SUBJECT_CAPTURE, 0);
2542 }
2543 static inline ReplacementPart SubjectCapture(int capture_index) {
2544 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2545 }
2546 static inline ReplacementPart SubjectPrefix() {
2547 return ReplacementPart(SUBJECT_PREFIX, 0);
2548 }
2549 static inline ReplacementPart SubjectSuffix(int subject_length) {
2550 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2551 }
2552 static inline ReplacementPart ReplacementString() {
2553 return ReplacementPart(REPLACEMENT_STRING, 0);
2554 }
2555 static inline ReplacementPart ReplacementSubString(int from, int to) {
2556 ASSERT(from >= 0);
2557 ASSERT(to > from);
2558 return ReplacementPart(-from, to);
2559 }
2560
2561 // If tag <= 0 then it is the negation of a start index of a substring of
2562 // the replacement pattern, otherwise it's a value from PartType.
2563 ReplacementPart(int tag, int data)
2564 : tag(tag), data(data) {
2565 // Must be non-positive or a PartType value.
2566 ASSERT(tag < NUMBER_OF_PART_TYPES);
2567 }
2568 // Either a value of PartType or a non-positive number that is
2569 // the negation of an index into the replacement string.
2570 int tag;
2571 // The data value's interpretation depends on the value of tag:
2572 // tag == SUBJECT_PREFIX ||
2573 // tag == SUBJECT_SUFFIX: data is unused.
2574 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2575 // tag == REPLACEMENT_SUBSTRING ||
2576 // tag == REPLACEMENT_STRING: data is index into array of substrings
2577 // of the replacement string.
2578 // tag <= 0: Temporary representation of the substring of the replacement
2579 // string ranging over -tag .. data.
2580 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2581 // substring objects.
2582 int data;
2583 };
2584
2585 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002586 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002587 Vector<Char> characters,
2588 int capture_count,
2589 int subject_length) {
2590 int length = characters.length();
2591 int last = 0;
2592 for (int i = 0; i < length; i++) {
2593 Char c = characters[i];
2594 if (c == '$') {
2595 int next_index = i + 1;
2596 if (next_index == length) { // No next character!
2597 break;
2598 }
2599 Char c2 = characters[next_index];
2600 switch (c2) {
2601 case '$':
2602 if (i > last) {
2603 // There is a substring before. Include the first "$".
2604 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2605 last = next_index + 1; // Continue after the second "$".
2606 } else {
2607 // Let the next substring start with the second "$".
2608 last = next_index;
2609 }
2610 i = next_index;
2611 break;
2612 case '`':
2613 if (i > last) {
2614 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2615 }
2616 parts->Add(ReplacementPart::SubjectPrefix());
2617 i = next_index;
2618 last = i + 1;
2619 break;
2620 case '\'':
2621 if (i > last) {
2622 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2623 }
2624 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2625 i = next_index;
2626 last = i + 1;
2627 break;
2628 case '&':
2629 if (i > last) {
2630 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2631 }
2632 parts->Add(ReplacementPart::SubjectMatch());
2633 i = next_index;
2634 last = i + 1;
2635 break;
2636 case '0':
2637 case '1':
2638 case '2':
2639 case '3':
2640 case '4':
2641 case '5':
2642 case '6':
2643 case '7':
2644 case '8':
2645 case '9': {
2646 int capture_ref = c2 - '0';
2647 if (capture_ref > capture_count) {
2648 i = next_index;
2649 continue;
2650 }
2651 int second_digit_index = next_index + 1;
2652 if (second_digit_index < length) {
2653 // Peek ahead to see if we have two digits.
2654 Char c3 = characters[second_digit_index];
2655 if ('0' <= c3 && c3 <= '9') { // Double digits.
2656 int double_digit_ref = capture_ref * 10 + c3 - '0';
2657 if (double_digit_ref <= capture_count) {
2658 next_index = second_digit_index;
2659 capture_ref = double_digit_ref;
2660 }
2661 }
2662 }
2663 if (capture_ref > 0) {
2664 if (i > last) {
2665 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2666 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002667 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002668 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2669 last = next_index + 1;
2670 }
2671 i = next_index;
2672 break;
2673 }
2674 default:
2675 i = next_index;
2676 break;
2677 }
2678 }
2679 }
2680 if (length > last) {
2681 if (last == 0) {
2682 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002683 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002684 } else {
2685 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2686 }
2687 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002688 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002689 }
2690
2691 ZoneList<ReplacementPart> parts_;
2692 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002693 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002694};
2695
2696
2697void CompiledReplacement::Compile(Handle<String> replacement,
2698 int capture_count,
2699 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002700 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002701 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002702 String::FlatContent content = replacement->GetFlatContent();
2703 ASSERT(content.IsFlat());
2704 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002705 simple_hint_ = ParseReplacementPattern(&parts_,
2706 content.ToAsciiVector(),
2707 capture_count,
2708 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002709 } else {
2710 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002711 simple_hint_ = ParseReplacementPattern(&parts_,
2712 content.ToUC16Vector(),
2713 capture_count,
2714 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002715 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002716 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002717 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002718 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002719 int substring_index = 0;
2720 for (int i = 0, n = parts_.length(); i < n; i++) {
2721 int tag = parts_[i].tag;
2722 if (tag <= 0) { // A replacement string slice.
2723 int from = -tag;
2724 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002725 replacement_substrings_.Add(
2726 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002727 parts_[i].tag = REPLACEMENT_SUBSTRING;
2728 parts_[i].data = substring_index;
2729 substring_index++;
2730 } else if (tag == REPLACEMENT_STRING) {
2731 replacement_substrings_.Add(replacement);
2732 parts_[i].data = substring_index;
2733 substring_index++;
2734 }
2735 }
2736}
2737
2738
2739void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2740 int match_from,
2741 int match_to,
2742 Handle<JSArray> last_match_info) {
2743 for (int i = 0, n = parts_.length(); i < n; i++) {
2744 ReplacementPart part = parts_[i];
2745 switch (part.tag) {
2746 case SUBJECT_PREFIX:
2747 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2748 break;
2749 case SUBJECT_SUFFIX: {
2750 int subject_length = part.data;
2751 if (match_to < subject_length) {
2752 builder->AddSubjectSlice(match_to, subject_length);
2753 }
2754 break;
2755 }
2756 case SUBJECT_CAPTURE: {
2757 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002758 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002759 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2760 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2761 if (from >= 0 && to > from) {
2762 builder->AddSubjectSlice(from, to);
2763 }
2764 break;
2765 }
2766 case REPLACEMENT_SUBSTRING:
2767 case REPLACEMENT_STRING:
2768 builder->AddString(replacement_substrings_[part.data]);
2769 break;
2770 default:
2771 UNREACHABLE();
2772 }
2773 }
2774}
2775
2776
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002777void FindAsciiStringIndices(Vector<const char> subject,
2778 char pattern,
2779 ZoneList<int>* indices,
2780 unsigned int limit) {
2781 ASSERT(limit > 0);
2782 // Collect indices of pattern in subject using memchr.
2783 // Stop after finding at most limit values.
2784 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2785 const char* subject_end = subject_start + subject.length();
2786 const char* pos = subject_start;
2787 while (limit > 0) {
2788 pos = reinterpret_cast<const char*>(
2789 memchr(pos, pattern, subject_end - pos));
2790 if (pos == NULL) return;
2791 indices->Add(static_cast<int>(pos - subject_start));
2792 pos++;
2793 limit--;
2794 }
2795}
2796
2797
2798template <typename SubjectChar, typename PatternChar>
2799void FindStringIndices(Isolate* isolate,
2800 Vector<const SubjectChar> subject,
2801 Vector<const PatternChar> pattern,
2802 ZoneList<int>* indices,
2803 unsigned int limit) {
2804 ASSERT(limit > 0);
2805 // Collect indices of pattern in subject.
2806 // Stop after finding at most limit values.
2807 int pattern_length = pattern.length();
2808 int index = 0;
2809 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2810 while (limit > 0) {
2811 index = search.Search(subject, index);
2812 if (index < 0) return;
2813 indices->Add(index);
2814 index += pattern_length;
2815 limit--;
2816 }
2817}
2818
2819
2820void FindStringIndicesDispatch(Isolate* isolate,
2821 String* subject,
2822 String* pattern,
2823 ZoneList<int>* indices,
2824 unsigned int limit) {
2825 {
2826 AssertNoAllocation no_gc;
2827 String::FlatContent subject_content = subject->GetFlatContent();
2828 String::FlatContent pattern_content = pattern->GetFlatContent();
2829 ASSERT(subject_content.IsFlat());
2830 ASSERT(pattern_content.IsFlat());
2831 if (subject_content.IsAscii()) {
2832 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2833 if (pattern_content.IsAscii()) {
2834 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2835 if (pattern_vector.length() == 1) {
2836 FindAsciiStringIndices(subject_vector,
2837 pattern_vector[0],
2838 indices,
2839 limit);
2840 } else {
2841 FindStringIndices(isolate,
2842 subject_vector,
2843 pattern_vector,
2844 indices,
2845 limit);
2846 }
2847 } else {
2848 FindStringIndices(isolate,
2849 subject_vector,
2850 pattern_content.ToUC16Vector(),
2851 indices,
2852 limit);
2853 }
2854 } else {
2855 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002856 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002857 FindStringIndices(isolate,
2858 subject_vector,
2859 pattern_content.ToAsciiVector(),
2860 indices,
2861 limit);
2862 } else {
2863 FindStringIndices(isolate,
2864 subject_vector,
2865 pattern_content.ToUC16Vector(),
2866 indices,
2867 limit);
2868 }
2869 }
2870 }
2871}
2872
2873
2874template<typename ResultSeqString>
2875MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2876 Isolate* isolate,
2877 Handle<String> subject,
2878 Handle<JSRegExp> pattern_regexp,
2879 Handle<String> replacement) {
2880 ASSERT(subject->IsFlat());
2881 ASSERT(replacement->IsFlat());
2882
2883 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2884 ZoneList<int> indices(8);
2885 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2886 String* pattern =
2887 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2888 int subject_len = subject->length();
2889 int pattern_len = pattern->length();
2890 int replacement_len = replacement->length();
2891
2892 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2893
2894 int matches = indices.length();
2895 if (matches == 0) return *subject;
2896
2897 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2898 int subject_pos = 0;
2899 int result_pos = 0;
2900
2901 Handle<ResultSeqString> result;
2902 if (ResultSeqString::kHasAsciiEncoding) {
2903 result = Handle<ResultSeqString>::cast(
2904 isolate->factory()->NewRawAsciiString(result_len));
2905 } else {
2906 result = Handle<ResultSeqString>::cast(
2907 isolate->factory()->NewRawTwoByteString(result_len));
2908 }
2909
2910 for (int i = 0; i < matches; i++) {
2911 // Copy non-matched subject content.
2912 if (subject_pos < indices.at(i)) {
2913 String::WriteToFlat(*subject,
2914 result->GetChars() + result_pos,
2915 subject_pos,
2916 indices.at(i));
2917 result_pos += indices.at(i) - subject_pos;
2918 }
2919
2920 // Replace match.
2921 if (replacement_len > 0) {
2922 String::WriteToFlat(*replacement,
2923 result->GetChars() + result_pos,
2924 0,
2925 replacement_len);
2926 result_pos += replacement_len;
2927 }
2928
2929 subject_pos = indices.at(i) + pattern_len;
2930 }
2931 // Add remaining subject content at the end.
2932 if (subject_pos < subject_len) {
2933 String::WriteToFlat(*subject,
2934 result->GetChars() + result_pos,
2935 subject_pos,
2936 subject_len);
2937 }
2938 return *result;
2939}
2940
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002941
lrn@chromium.org303ada72010-10-27 09:33:13 +00002942MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002943 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002944 String* subject,
2945 JSRegExp* regexp,
2946 String* replacement,
2947 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002948 ASSERT(subject->IsFlat());
2949 ASSERT(replacement->IsFlat());
2950
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002951 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002952
2953 int length = subject->length();
2954 Handle<String> subject_handle(subject);
2955 Handle<JSRegExp> regexp_handle(regexp);
2956 Handle<String> replacement_handle(replacement);
2957 Handle<JSArray> last_match_info_handle(last_match_info);
2958 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2959 subject_handle,
2960 0,
2961 last_match_info_handle);
2962 if (match.is_null()) {
2963 return Failure::Exception();
2964 }
2965 if (match->IsNull()) {
2966 return *subject_handle;
2967 }
2968
2969 int capture_count = regexp_handle->CaptureCount();
2970
2971 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002972 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002973 CompiledReplacement compiled_replacement;
2974 compiled_replacement.Compile(replacement_handle,
2975 capture_count,
2976 length);
2977
2978 bool is_global = regexp_handle->GetFlags().is_global();
2979
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002980 // Shortcut for simple non-regexp global replacements
2981 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002982 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002983 compiled_replacement.simple_hint()) {
2984 if (subject_handle->HasOnlyAsciiChars() &&
2985 replacement_handle->HasOnlyAsciiChars()) {
2986 return StringReplaceStringWithString<SeqAsciiString>(
2987 isolate, subject_handle, regexp_handle, replacement_handle);
2988 } else {
2989 return StringReplaceStringWithString<SeqTwoByteString>(
2990 isolate, subject_handle, regexp_handle, replacement_handle);
2991 }
2992 }
2993
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002994 // Guessing the number of parts that the final result string is built
2995 // from. Global regexps can match any number of times, so we guess
2996 // conservatively.
2997 int expected_parts =
2998 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002999 ReplacementStringBuilder builder(isolate->heap(),
3000 subject_handle,
3001 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003002
3003 // Index of end of last match.
3004 int prev = 0;
3005
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003006 // Number of parts added by compiled replacement plus preceeding
3007 // string and possibly suffix after last match. It is possible for
3008 // all components to use two elements when encoded as two smis.
3009 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003010 bool matched = true;
3011 do {
3012 ASSERT(last_match_info_handle->HasFastElements());
3013 // Increase the capacity of the builder before entering local handle-scope,
3014 // so its internal buffer can safely allocate a new handle if it grows.
3015 builder.EnsureCapacity(parts_added_per_loop);
3016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003017 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003018 int start, end;
3019 {
3020 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003021 FixedArray* match_info_array =
3022 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003023
3024 ASSERT_EQ(capture_count * 2 + 2,
3025 RegExpImpl::GetLastCaptureCount(match_info_array));
3026 start = RegExpImpl::GetCapture(match_info_array, 0);
3027 end = RegExpImpl::GetCapture(match_info_array, 1);
3028 }
3029
3030 if (prev < start) {
3031 builder.AddSubjectSlice(prev, start);
3032 }
3033 compiled_replacement.Apply(&builder,
3034 start,
3035 end,
3036 last_match_info_handle);
3037 prev = end;
3038
3039 // Only continue checking for global regexps.
3040 if (!is_global) break;
3041
3042 // Continue from where the match ended, unless it was an empty match.
3043 int next = end;
3044 if (start == end) {
3045 next = end + 1;
3046 if (next > length) break;
3047 }
3048
3049 match = RegExpImpl::Exec(regexp_handle,
3050 subject_handle,
3051 next,
3052 last_match_info_handle);
3053 if (match.is_null()) {
3054 return Failure::Exception();
3055 }
3056 matched = !match->IsNull();
3057 } while (matched);
3058
3059 if (prev < length) {
3060 builder.AddSubjectSlice(prev, length);
3061 }
3062
3063 return *(builder.ToString());
3064}
3065
3066
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003067template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003068MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003069 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003070 String* subject,
3071 JSRegExp* regexp,
3072 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003073 ASSERT(subject->IsFlat());
3074
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003075 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003076
3077 Handle<String> subject_handle(subject);
3078 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003079
3080 // Shortcut for simple non-regexp global replacements
3081 if (regexp_handle->GetFlags().is_global() &&
3082 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3083 Handle<String> empty_string_handle(HEAP->empty_string());
3084 if (subject_handle->HasOnlyAsciiChars()) {
3085 return StringReplaceStringWithString<SeqAsciiString>(
3086 isolate, subject_handle, regexp_handle, empty_string_handle);
3087 } else {
3088 return StringReplaceStringWithString<SeqTwoByteString>(
3089 isolate, subject_handle, regexp_handle, empty_string_handle);
3090 }
3091 }
3092
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003093 Handle<JSArray> last_match_info_handle(last_match_info);
3094 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3095 subject_handle,
3096 0,
3097 last_match_info_handle);
3098 if (match.is_null()) return Failure::Exception();
3099 if (match->IsNull()) return *subject_handle;
3100
3101 ASSERT(last_match_info_handle->HasFastElements());
3102
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003103 int start, end;
3104 {
3105 AssertNoAllocation match_info_array_is_not_in_a_handle;
3106 FixedArray* match_info_array =
3107 FixedArray::cast(last_match_info_handle->elements());
3108
3109 start = RegExpImpl::GetCapture(match_info_array, 0);
3110 end = RegExpImpl::GetCapture(match_info_array, 1);
3111 }
3112
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003113 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003114 int new_length = length - (end - start);
3115 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003116 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003117 }
3118 Handle<ResultSeqString> answer;
3119 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003120 answer = Handle<ResultSeqString>::cast(
3121 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003122 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003123 answer = Handle<ResultSeqString>::cast(
3124 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003125 }
3126
3127 // If the regexp isn't global, only match once.
3128 if (!regexp_handle->GetFlags().is_global()) {
3129 if (start > 0) {
3130 String::WriteToFlat(*subject_handle,
3131 answer->GetChars(),
3132 0,
3133 start);
3134 }
3135 if (end < length) {
3136 String::WriteToFlat(*subject_handle,
3137 answer->GetChars() + start,
3138 end,
3139 length);
3140 }
3141 return *answer;
3142 }
3143
3144 int prev = 0; // Index of end of last match.
3145 int next = 0; // Start of next search (prev unless last match was empty).
3146 int position = 0;
3147
3148 do {
3149 if (prev < start) {
3150 // Add substring subject[prev;start] to answer string.
3151 String::WriteToFlat(*subject_handle,
3152 answer->GetChars() + position,
3153 prev,
3154 start);
3155 position += start - prev;
3156 }
3157 prev = end;
3158 next = end;
3159 // Continue from where the match ended, unless it was an empty match.
3160 if (start == end) {
3161 next++;
3162 if (next > length) break;
3163 }
3164 match = RegExpImpl::Exec(regexp_handle,
3165 subject_handle,
3166 next,
3167 last_match_info_handle);
3168 if (match.is_null()) return Failure::Exception();
3169 if (match->IsNull()) break;
3170
3171 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003172 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003173 {
3174 AssertNoAllocation match_info_array_is_not_in_a_handle;
3175 FixedArray* match_info_array =
3176 FixedArray::cast(last_match_info_handle->elements());
3177 start = RegExpImpl::GetCapture(match_info_array, 0);
3178 end = RegExpImpl::GetCapture(match_info_array, 1);
3179 }
3180 } while (true);
3181
3182 if (prev < length) {
3183 // Add substring subject[prev;length] to answer string.
3184 String::WriteToFlat(*subject_handle,
3185 answer->GetChars() + position,
3186 prev,
3187 length);
3188 position += length - prev;
3189 }
3190
3191 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003192 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003193 }
3194
3195 // Shorten string and fill
3196 int string_size = ResultSeqString::SizeFor(position);
3197 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3198 int delta = allocated_string_size - string_size;
3199
3200 answer->set_length(position);
3201 if (delta == 0) return *answer;
3202
3203 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003204 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003205 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003206 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003207 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003208
3209 return *answer;
3210}
3211
3212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003213RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003214 ASSERT(args.length() == 4);
3215
3216 CONVERT_CHECKED(String, subject, args[0]);
3217 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003218 Object* flat_subject;
3219 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3220 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3221 return maybe_flat_subject;
3222 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003223 }
3224 subject = String::cast(flat_subject);
3225 }
3226
3227 CONVERT_CHECKED(String, replacement, args[2]);
3228 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003229 Object* flat_replacement;
3230 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3231 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3232 return maybe_flat_replacement;
3233 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003234 }
3235 replacement = String::cast(flat_replacement);
3236 }
3237
3238 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3239 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3240
3241 ASSERT(last_match_info->HasFastElements());
3242
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003243 if (replacement->length() == 0) {
3244 if (subject->HasOnlyAsciiChars()) {
3245 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003246 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003247 } else {
3248 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003249 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003250 }
3251 }
3252
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003253 return StringReplaceRegExpWithString(isolate,
3254 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003255 regexp,
3256 replacement,
3257 last_match_info);
3258}
3259
3260
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003261Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3262 Handle<String> subject,
3263 Handle<String> search,
3264 Handle<String> replace,
3265 bool* found,
3266 int recursion_limit) {
3267 if (recursion_limit == 0) return Handle<String>::null();
3268 if (subject->IsConsString()) {
3269 ConsString* cons = ConsString::cast(*subject);
3270 Handle<String> first = Handle<String>(cons->first());
3271 Handle<String> second = Handle<String>(cons->second());
3272 Handle<String> new_first =
3273 StringReplaceOneCharWithString(isolate,
3274 first,
3275 search,
3276 replace,
3277 found,
3278 recursion_limit - 1);
3279 if (*found) return isolate->factory()->NewConsString(new_first, second);
3280 if (new_first.is_null()) return new_first;
3281
3282 Handle<String> new_second =
3283 StringReplaceOneCharWithString(isolate,
3284 second,
3285 search,
3286 replace,
3287 found,
3288 recursion_limit - 1);
3289 if (*found) return isolate->factory()->NewConsString(first, new_second);
3290 if (new_second.is_null()) return new_second;
3291
3292 return subject;
3293 } else {
3294 int index = StringMatch(isolate, subject, search, 0);
3295 if (index == -1) return subject;
3296 *found = true;
3297 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3298 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3299 Handle<String> second =
3300 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3301 return isolate->factory()->NewConsString(cons1, second);
3302 }
3303}
3304
3305
3306RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3307 ASSERT(args.length() == 3);
3308 HandleScope scope(isolate);
3309 CONVERT_ARG_CHECKED(String, subject, 0);
3310 CONVERT_ARG_CHECKED(String, search, 1);
3311 CONVERT_ARG_CHECKED(String, replace, 2);
3312
3313 // If the cons string tree is too deep, we simply abort the recursion and
3314 // retry with a flattened subject string.
3315 const int kRecursionLimit = 0x1000;
3316 bool found = false;
3317 Handle<String> result =
3318 Runtime::StringReplaceOneCharWithString(isolate,
3319 subject,
3320 search,
3321 replace,
3322 &found,
3323 kRecursionLimit);
3324 if (!result.is_null()) return *result;
3325 return *Runtime::StringReplaceOneCharWithString(isolate,
3326 FlattenGetString(subject),
3327 search,
3328 replace,
3329 &found,
3330 kRecursionLimit);
3331}
3332
3333
ager@chromium.org7c537e22008-10-16 08:43:32 +00003334// Perform string match of pattern on subject, starting at start index.
3335// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003336// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003337int Runtime::StringMatch(Isolate* isolate,
3338 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003339 Handle<String> pat,
3340 int start_index) {
3341 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003342 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003343
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003344 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003345 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003346
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003347 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003348 if (start_index + pattern_length > subject_length) return -1;
3349
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003350 if (!sub->IsFlat()) FlattenString(sub);
3351 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003352
ager@chromium.org7c537e22008-10-16 08:43:32 +00003353 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003354 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003355 String::FlatContent seq_sub = sub->GetFlatContent();
3356 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003357
ager@chromium.org7c537e22008-10-16 08:43:32 +00003358 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003359 if (seq_pat.IsAscii()) {
3360 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3361 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003362 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003363 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003364 pat_vector,
3365 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003366 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003367 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003368 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003369 pat_vector,
3370 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003371 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003372 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3373 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003374 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003375 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003376 pat_vector,
3377 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003378 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003379 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003380 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003381 pat_vector,
3382 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003383}
3384
3385
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003386RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003387 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003388 ASSERT(args.length() == 3);
3389
ager@chromium.org7c537e22008-10-16 08:43:32 +00003390 CONVERT_ARG_CHECKED(String, sub, 0);
3391 CONVERT_ARG_CHECKED(String, pat, 1);
3392
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003393 Object* index = args[2];
3394 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003395 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003396
ager@chromium.org870a0b62008-11-04 11:43:05 +00003397 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003398 int position =
3399 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003400 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401}
3402
3403
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003404template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003405static int StringMatchBackwards(Vector<const schar> subject,
3406 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003407 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003408 int pattern_length = pattern.length();
3409 ASSERT(pattern_length >= 1);
3410 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003411
3412 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003413 for (int i = 0; i < pattern_length; i++) {
3414 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003415 if (c > String::kMaxAsciiCharCode) {
3416 return -1;
3417 }
3418 }
3419 }
3420
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003421 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003422 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003423 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003424 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003425 while (j < pattern_length) {
3426 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003427 break;
3428 }
3429 j++;
3430 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003431 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003432 return i;
3433 }
3434 }
3435 return -1;
3436}
3437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003438RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003439 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003440 ASSERT(args.length() == 3);
3441
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003442 CONVERT_ARG_CHECKED(String, sub, 0);
3443 CONVERT_ARG_CHECKED(String, pat, 1);
3444
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003445 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003446 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003447 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003449 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003450 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003451
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003452 if (start_index + pat_length > sub_length) {
3453 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003454 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003455
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003456 if (pat_length == 0) {
3457 return Smi::FromInt(start_index);
3458 }
3459
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003460 if (!sub->IsFlat()) FlattenString(sub);
3461 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003462
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003463 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003464 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3465
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003466 String::FlatContent sub_content = sub->GetFlatContent();
3467 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003468
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003469 if (pat_content.IsAscii()) {
3470 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3471 if (sub_content.IsAscii()) {
3472 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003473 pat_vector,
3474 start_index);
3475 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003476 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003477 pat_vector,
3478 start_index);
3479 }
3480 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003481 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3482 if (sub_content.IsAscii()) {
3483 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003484 pat_vector,
3485 start_index);
3486 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003487 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003488 pat_vector,
3489 start_index);
3490 }
3491 }
3492
3493 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003494}
3495
3496
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003497RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003498 NoHandleAllocation ha;
3499 ASSERT(args.length() == 2);
3500
3501 CONVERT_CHECKED(String, str1, args[0]);
3502 CONVERT_CHECKED(String, str2, args[1]);
3503
3504 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003505 int str1_length = str1->length();
3506 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003507
3508 // Decide trivial cases without flattening.
3509 if (str1_length == 0) {
3510 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3511 return Smi::FromInt(-str2_length);
3512 } else {
3513 if (str2_length == 0) return Smi::FromInt(str1_length);
3514 }
3515
3516 int end = str1_length < str2_length ? str1_length : str2_length;
3517
3518 // No need to flatten if we are going to find the answer on the first
3519 // character. At this point we know there is at least one character
3520 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003521 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003522 if (d != 0) return Smi::FromInt(d);
3523
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003524 str1->TryFlatten();
3525 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003526
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003527 StringInputBuffer& buf1 =
3528 *isolate->runtime_state()->string_locale_compare_buf1();
3529 StringInputBuffer& buf2 =
3530 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003531
3532 buf1.Reset(str1);
3533 buf2.Reset(str2);
3534
3535 for (int i = 0; i < end; i++) {
3536 uint16_t char1 = buf1.GetNext();
3537 uint16_t char2 = buf2.GetNext();
3538 if (char1 != char2) return Smi::FromInt(char1 - char2);
3539 }
3540
3541 return Smi::FromInt(str1_length - str2_length);
3542}
3543
3544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003545RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003546 NoHandleAllocation ha;
3547 ASSERT(args.length() == 3);
3548
3549 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003550 int start, end;
3551 // We have a fast integer-only case here to avoid a conversion to double in
3552 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003553 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3554 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3555 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3556 start = from_number;
3557 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003558 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003559 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3560 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003561 start = FastD2I(from_number);
3562 end = FastD2I(to_number);
3563 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003564 RUNTIME_ASSERT(end >= start);
3565 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003566 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003567 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003568 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003569}
3570
3571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003572RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003573 ASSERT_EQ(3, args.length());
3574
3575 CONVERT_ARG_CHECKED(String, subject, 0);
3576 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3577 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3578 HandleScope handles;
3579
3580 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3581
3582 if (match.is_null()) {
3583 return Failure::Exception();
3584 }
3585 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003586 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003587 }
3588 int length = subject->length();
3589
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003590 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003591 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003592 int start;
3593 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003594 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003595 {
3596 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003597 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003598 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3599 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3600 }
3601 offsets.Add(start);
3602 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003603 if (start == end) if (++end > length) break;
3604 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003605 if (match.is_null()) {
3606 return Failure::Exception();
3607 }
3608 } while (!match->IsNull());
3609 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003610 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003611 Handle<String> substring = isolate->factory()->
3612 NewSubString(subject, offsets.at(0), offsets.at(1));
3613 elements->set(0, *substring);
3614 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003615 int from = offsets.at(i * 2);
3616 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003617 Handle<String> substring = isolate->factory()->
3618 NewProperSubString(subject, from, to);
3619 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003621 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003622 result->set_length(Smi::FromInt(matches));
3623 return *result;
3624}
3625
3626
lrn@chromium.org25156de2010-04-06 13:10:27 +00003627// Two smis before and after the match, for very long strings.
3628const int kMaxBuilderEntriesPerRegExpMatch = 5;
3629
3630
3631static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3632 Handle<JSArray> last_match_info,
3633 int match_start,
3634 int match_end) {
3635 // Fill last_match_info with a single capture.
3636 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3637 AssertNoAllocation no_gc;
3638 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3639 RegExpImpl::SetLastCaptureCount(elements, 2);
3640 RegExpImpl::SetLastInput(elements, *subject);
3641 RegExpImpl::SetLastSubject(elements, *subject);
3642 RegExpImpl::SetCapture(elements, 0, match_start);
3643 RegExpImpl::SetCapture(elements, 1, match_end);
3644}
3645
3646
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003647template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003648static bool SearchStringMultiple(Isolate* isolate,
3649 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003650 Vector<const PatternChar> pattern,
3651 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003652 FixedArrayBuilder* builder,
3653 int* match_pos) {
3654 int pos = *match_pos;
3655 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003656 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003657 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003658 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003659 while (pos <= max_search_start) {
3660 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3661 *match_pos = pos;
3662 return false;
3663 }
3664 // Position of end of previous match.
3665 int match_end = pos + pattern_length;
3666 int new_pos = search.Search(subject, match_end);
3667 if (new_pos >= 0) {
3668 // A match.
3669 if (new_pos > match_end) {
3670 ReplacementStringBuilder::AddSubjectSlice(builder,
3671 match_end,
3672 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003673 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003674 pos = new_pos;
3675 builder->Add(pattern_string);
3676 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003677 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003678 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003679 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003680
lrn@chromium.org25156de2010-04-06 13:10:27 +00003681 if (pos < max_search_start) {
3682 ReplacementStringBuilder::AddSubjectSlice(builder,
3683 pos + pattern_length,
3684 subject_length);
3685 }
3686 *match_pos = pos;
3687 return true;
3688}
3689
3690
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003691static bool SearchStringMultiple(Isolate* isolate,
3692 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003693 Handle<String> pattern,
3694 Handle<JSArray> last_match_info,
3695 FixedArrayBuilder* builder) {
3696 ASSERT(subject->IsFlat());
3697 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003698
3699 // Treating as if a previous match was before first character.
3700 int match_pos = -pattern->length();
3701
3702 for (;;) { // Break when search complete.
3703 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3704 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003705 String::FlatContent subject_content = subject->GetFlatContent();
3706 String::FlatContent pattern_content = pattern->GetFlatContent();
3707 if (subject_content.IsAscii()) {
3708 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3709 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003710 if (SearchStringMultiple(isolate,
3711 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003712 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003713 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003714 builder,
3715 &match_pos)) break;
3716 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003717 if (SearchStringMultiple(isolate,
3718 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003719 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003720 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003721 builder,
3722 &match_pos)) break;
3723 }
3724 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003725 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3726 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003727 if (SearchStringMultiple(isolate,
3728 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003729 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003730 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003731 builder,
3732 &match_pos)) break;
3733 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003734 if (SearchStringMultiple(isolate,
3735 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003736 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003737 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003738 builder,
3739 &match_pos)) break;
3740 }
3741 }
3742 }
3743
3744 if (match_pos >= 0) {
3745 SetLastMatchInfoNoCaptures(subject,
3746 last_match_info,
3747 match_pos,
3748 match_pos + pattern->length());
3749 return true;
3750 }
3751 return false; // No matches at all.
3752}
3753
3754
3755static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003756 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003757 Handle<String> subject,
3758 Handle<JSRegExp> regexp,
3759 Handle<JSArray> last_match_array,
3760 FixedArrayBuilder* builder) {
3761 ASSERT(subject->IsFlat());
3762 int match_start = -1;
3763 int match_end = 0;
3764 int pos = 0;
3765 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3766 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3767
3768 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003769 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003770 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003771 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003772
3773 for (;;) { // Break on failure, return on exception.
3774 RegExpImpl::IrregexpResult result =
3775 RegExpImpl::IrregexpExecOnce(regexp,
3776 subject,
3777 pos,
3778 register_vector);
3779 if (result == RegExpImpl::RE_SUCCESS) {
3780 match_start = register_vector[0];
3781 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3782 if (match_end < match_start) {
3783 ReplacementStringBuilder::AddSubjectSlice(builder,
3784 match_end,
3785 match_start);
3786 }
3787 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003788 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003789 if (!first) {
3790 builder->Add(*isolate->factory()->NewProperSubString(subject,
3791 match_start,
3792 match_end));
3793 } else {
3794 builder->Add(*isolate->factory()->NewSubString(subject,
3795 match_start,
3796 match_end));
3797 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003798 if (match_start != match_end) {
3799 pos = match_end;
3800 } else {
3801 pos = match_end + 1;
3802 if (pos > subject_length) break;
3803 }
3804 } else if (result == RegExpImpl::RE_FAILURE) {
3805 break;
3806 } else {
3807 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3808 return result;
3809 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003810 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003811 }
3812
3813 if (match_start >= 0) {
3814 if (match_end < subject_length) {
3815 ReplacementStringBuilder::AddSubjectSlice(builder,
3816 match_end,
3817 subject_length);
3818 }
3819 SetLastMatchInfoNoCaptures(subject,
3820 last_match_array,
3821 match_start,
3822 match_end);
3823 return RegExpImpl::RE_SUCCESS;
3824 } else {
3825 return RegExpImpl::RE_FAILURE; // No matches at all.
3826 }
3827}
3828
3829
3830static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003831 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003832 Handle<String> subject,
3833 Handle<JSRegExp> regexp,
3834 Handle<JSArray> last_match_array,
3835 FixedArrayBuilder* builder) {
3836
3837 ASSERT(subject->IsFlat());
3838 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3839 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3840
3841 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003842 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003843
3844 RegExpImpl::IrregexpResult result =
3845 RegExpImpl::IrregexpExecOnce(regexp,
3846 subject,
3847 0,
3848 register_vector);
3849
3850 int capture_count = regexp->CaptureCount();
3851 int subject_length = subject->length();
3852
3853 // Position to search from.
3854 int pos = 0;
3855 // End of previous match. Differs from pos if match was empty.
3856 int match_end = 0;
3857 if (result == RegExpImpl::RE_SUCCESS) {
3858 // Need to keep a copy of the previous match for creating last_match_info
3859 // at the end, so we have two vectors that we swap between.
3860 OffsetsVector registers2(required_registers);
3861 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003862 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003863 do {
3864 int match_start = register_vector[0];
3865 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3866 if (match_end < match_start) {
3867 ReplacementStringBuilder::AddSubjectSlice(builder,
3868 match_end,
3869 match_start);
3870 }
3871 match_end = register_vector[1];
3872
3873 {
3874 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003875 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003876 // Arguments array to replace function is match, captures, index and
3877 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003878 Handle<FixedArray> elements =
3879 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003880 Handle<String> match;
3881 if (!first) {
3882 match = isolate->factory()->NewProperSubString(subject,
3883 match_start,
3884 match_end);
3885 } else {
3886 match = isolate->factory()->NewSubString(subject,
3887 match_start,
3888 match_end);
3889 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003890 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003891 for (int i = 1; i <= capture_count; i++) {
3892 int start = register_vector[i * 2];
3893 if (start >= 0) {
3894 int end = register_vector[i * 2 + 1];
3895 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003896 Handle<String> substring;
3897 if (!first) {
3898 substring = isolate->factory()->NewProperSubString(subject,
3899 start,
3900 end);
3901 } else {
3902 substring = isolate->factory()->NewSubString(subject, start, end);
3903 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003904 elements->set(i, *substring);
3905 } else {
3906 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003907 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003908 }
3909 }
3910 elements->set(capture_count + 1, Smi::FromInt(match_start));
3911 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003912 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003913 }
3914 // Swap register vectors, so the last successful match is in
3915 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003916 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003917 prev_register_vector = register_vector;
3918 register_vector = tmp;
3919
3920 if (match_end > match_start) {
3921 pos = match_end;
3922 } else {
3923 pos = match_end + 1;
3924 if (pos > subject_length) {
3925 break;
3926 }
3927 }
3928
3929 result = RegExpImpl::IrregexpExecOnce(regexp,
3930 subject,
3931 pos,
3932 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003933 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003934 } while (result == RegExpImpl::RE_SUCCESS);
3935
3936 if (result != RegExpImpl::RE_EXCEPTION) {
3937 // Finished matching, with at least one match.
3938 if (match_end < subject_length) {
3939 ReplacementStringBuilder::AddSubjectSlice(builder,
3940 match_end,
3941 subject_length);
3942 }
3943
3944 int last_match_capture_count = (capture_count + 1) * 2;
3945 int last_match_array_size =
3946 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3947 last_match_array->EnsureSize(last_match_array_size);
3948 AssertNoAllocation no_gc;
3949 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3950 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3951 RegExpImpl::SetLastSubject(elements, *subject);
3952 RegExpImpl::SetLastInput(elements, *subject);
3953 for (int i = 0; i < last_match_capture_count; i++) {
3954 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3955 }
3956 return RegExpImpl::RE_SUCCESS;
3957 }
3958 }
3959 // No matches at all, return failure or exception result directly.
3960 return result;
3961}
3962
3963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003964RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003965 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003966 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003967
3968 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003969 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003970 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3971 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3972 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3973
3974 ASSERT(last_match_info->HasFastElements());
3975 ASSERT(regexp->GetFlags().is_global());
3976 Handle<FixedArray> result_elements;
3977 if (result_array->HasFastElements()) {
3978 result_elements =
3979 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003980 }
3981 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003982 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003983 }
3984 FixedArrayBuilder builder(result_elements);
3985
3986 if (regexp->TypeTag() == JSRegExp::ATOM) {
3987 Handle<String> pattern(
3988 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003989 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003990 if (SearchStringMultiple(isolate, subject, pattern,
3991 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003992 return *builder.ToJSArray(result_array);
3993 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003994 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003995 }
3996
3997 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3998
3999 RegExpImpl::IrregexpResult result;
4000 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004001 result = SearchRegExpNoCaptureMultiple(isolate,
4002 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004003 regexp,
4004 last_match_info,
4005 &builder);
4006 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 result = SearchRegExpMultiple(isolate,
4008 subject,
4009 regexp,
4010 last_match_info,
4011 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004012 }
4013 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004014 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004015 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4016 return Failure::Exception();
4017}
4018
4019
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004020RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 NoHandleAllocation ha;
4022 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004023 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004024 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004025
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004026 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004027 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004028 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004029 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004030 // Character array used for conversion.
4031 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004032 return isolate->heap()->
4033 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004034 }
4035 }
4036
4037 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004038 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004039 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004040 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004041 }
4042 if (isinf(value)) {
4043 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004044 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004046 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004049 MaybeObject* result =
4050 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004051 DeleteArray(str);
4052 return result;
4053}
4054
4055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004056RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057 NoHandleAllocation ha;
4058 ASSERT(args.length() == 2);
4059
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004060 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004061 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004062 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 }
4064 if (isinf(value)) {
4065 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004066 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004068 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004070 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004071 int f = FastD2I(f_number);
4072 RUNTIME_ASSERT(f >= 0);
4073 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004074 MaybeObject* res =
4075 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004076 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004077 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004078}
4079
4080
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004081RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 NoHandleAllocation ha;
4083 ASSERT(args.length() == 2);
4084
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004085 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004087 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 }
4089 if (isinf(value)) {
4090 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004091 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004093 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004095 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004096 int f = FastD2I(f_number);
4097 RUNTIME_ASSERT(f >= -1 && f <= 20);
4098 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004099 MaybeObject* res =
4100 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004101 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004102 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103}
4104
4105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004106RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 NoHandleAllocation ha;
4108 ASSERT(args.length() == 2);
4109
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004110 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004111 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004112 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 }
4114 if (isinf(value)) {
4115 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004116 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004118 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004120 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004121 int f = FastD2I(f_number);
4122 RUNTIME_ASSERT(f >= 1 && f <= 21);
4123 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004124 MaybeObject* res =
4125 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004126 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004127 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004128}
4129
4130
4131// Returns a single character string where first character equals
4132// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004133static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004134 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004135 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004136 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004137 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004138 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004139 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004140}
4141
4142
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004143MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4144 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004145 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004146 // Handle [] indexing on Strings
4147 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004148 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4149 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004150 }
4151
4152 // Handle [] indexing on String objects
4153 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004154 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4155 Handle<Object> result =
4156 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4157 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004158 }
4159
4160 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004161 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004162 }
4163
4164 return object->GetElement(index);
4165}
4166
4167
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004168MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4169 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004170 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004171 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004172
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004174 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004175 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176 isolate->factory()->NewTypeError("non_object_property_load",
4177 HandleVector(args, 2));
4178 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004179 }
4180
4181 // Check if the given key is an array index.
4182 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004183 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004184 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 }
4186
4187 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004188 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004189 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004190 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004192 bool has_pending_exception = false;
4193 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004194 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004195 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004196 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197 }
4198
ager@chromium.org32912102009-01-16 10:38:43 +00004199 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004200 // the element if so.
4201 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004202 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004204 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004205 }
4206}
4207
4208
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004209RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004210 NoHandleAllocation ha;
4211 ASSERT(args.length() == 2);
4212
4213 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004214 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004215
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217}
4218
4219
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004220// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004221RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004222 NoHandleAllocation ha;
4223 ASSERT(args.length() == 2);
4224
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004225 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004226 // itself.
4227 //
4228 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004229 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004230 // global proxy object never has properties. This is the case
4231 // because the global proxy object forwards everything to its hidden
4232 // prototype including local lookups.
4233 //
4234 // Additionally, we need to make sure that we do not cache results
4235 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004236 if (args[0]->IsJSObject()) {
4237 if (!args[0]->IsJSGlobalProxy() &&
4238 !args[0]->IsAccessCheckNeeded() &&
4239 args[1]->IsString()) {
4240 JSObject* receiver = JSObject::cast(args[0]);
4241 String* key = String::cast(args[1]);
4242 if (receiver->HasFastProperties()) {
4243 // Attempt to use lookup cache.
4244 Map* receiver_map = receiver->map();
4245 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4246 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4247 if (offset != -1) {
4248 Object* value = receiver->FastPropertyAt(offset);
4249 return value->IsTheHole()
4250 ? isolate->heap()->undefined_value()
4251 : value;
4252 }
4253 // Lookup cache miss. Perform lookup and update the cache if
4254 // appropriate.
4255 LookupResult result(isolate);
4256 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004257 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004258 int offset = result.GetFieldIndex();
4259 keyed_lookup_cache->Update(receiver_map, key, offset);
4260 return receiver->FastPropertyAt(offset);
4261 }
4262 } else {
4263 // Attempt dictionary lookup.
4264 StringDictionary* dictionary = receiver->property_dictionary();
4265 int entry = dictionary->FindEntry(key);
4266 if ((entry != StringDictionary::kNotFound) &&
4267 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4268 Object* value = dictionary->ValueAt(entry);
4269 if (!receiver->IsGlobalObject()) return value;
4270 value = JSGlobalPropertyCell::cast(value)->value();
4271 if (!value->IsTheHole()) return value;
4272 // If value is the hole do the general lookup.
4273 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004274 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004275 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4276 // JSObject without a string key. If the key is a Smi, check for a
4277 // definite out-of-bounds access to elements, which is a strong indicator
4278 // that subsequent accesses will also call the runtime. Proactively
4279 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4280 // doubles for those future calls in the case that the elements would
4281 // become FAST_DOUBLE_ELEMENTS.
4282 Handle<JSObject> js_object(args.at<JSObject>(0));
4283 ElementsKind elements_kind = js_object->GetElementsKind();
4284 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4285 elements_kind == FAST_DOUBLE_ELEMENTS) {
4286 FixedArrayBase* elements = js_object->elements();
4287 if (args.at<Smi>(1)->value() >= elements->length()) {
4288 MaybeObject* maybe_object = TransitionElements(js_object,
4289 FAST_ELEMENTS,
4290 isolate);
4291 if (maybe_object->IsFailure()) return maybe_object;
4292 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004293 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004294 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004295 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4296 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004297 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004298 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004299 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004300 if (index >= 0 && index < str->length()) {
4301 Handle<Object> result = GetCharAt(str, index);
4302 return *result;
4303 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004304 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004305
4306 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004307 return Runtime::GetObjectProperty(isolate,
4308 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004309 args.at<Object>(1));
4310}
4311
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004312// Implements part of 8.12.9 DefineOwnProperty.
4313// There are 3 cases that lead here:
4314// Step 4b - define a new accessor property.
4315// Steps 9c & 12 - replace an existing data property with an accessor property.
4316// Step 12 - update an existing accessor property with an accessor or generic
4317// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004318RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004319 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004320 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004321 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4322 CONVERT_CHECKED(String, name, args[1]);
4323 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004324 Object* fun = args[3];
ager@chromium.org5c838252010-02-19 08:53:10 +00004325 CONVERT_CHECKED(Smi, flag_attr, args[4]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004326
ager@chromium.org5c838252010-02-19 08:53:10 +00004327 int unchecked = flag_attr->value();
4328 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004329 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004330
4331 RUNTIME_ASSERT(!obj->IsNull());
4332 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004333 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4334}
4335
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004336// Implements part of 8.12.9 DefineOwnProperty.
4337// There are 3 cases that lead here:
4338// Step 4a - define a new data property.
4339// Steps 9b & 12 - replace an existing accessor property with a data property.
4340// Step 12 - update an existing data property with a data or generic
4341// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004342RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004343 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004344 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004345 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4346 CONVERT_ARG_CHECKED(String, name, 1);
4347 Handle<Object> obj_value = args.at<Object>(2);
ager@chromium.org5c838252010-02-19 08:53:10 +00004348 CONVERT_CHECKED(Smi, flag, args[3]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004349
ager@chromium.org5c838252010-02-19 08:53:10 +00004350 int unchecked = flag->value();
4351 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004352 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4353
4354 // Check if this is an element.
4355 uint32_t index;
4356 bool is_element = name->AsArrayIndex(&index);
4357
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004358 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004359 // If elements are in fast case we always implicitly assume that:
4360 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004361 if (is_element && (attr != NONE ||
4362 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004363 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004364 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004365 // We do not need to do access checks here since these has already
4366 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004367 Handle<Object> proto(js_object->GetPrototype());
4368 // If proxy is detached, ignore the assignment. Alternatively,
4369 // we could throw an exception.
4370 if (proto->IsNull()) return *obj_value;
4371 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004372 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004373
4374 // Don't allow element properties to be redefined on objects with external
4375 // array elements.
4376 if (js_object->HasExternalArrayElements()) {
4377 Handle<Object> args[2] = { js_object, name };
4378 Handle<Object> error =
4379 isolate->factory()->NewTypeError("redef_external_array_element",
4380 HandleVector(args, 2));
4381 return isolate->Throw(*error);
4382 }
4383
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004384 Handle<SeededNumberDictionary> dictionary =
4385 JSObject::NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004386 // Make sure that we never go back to fast case.
4387 dictionary->set_requires_slow_elements();
4388 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004389 Handle<SeededNumberDictionary> extended_dictionary =
4390 SeededNumberDictionary::Set(dictionary, index, obj_value, details);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004391 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004392 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004393 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4394 } else {
4395 js_object->set_elements(*extended_dictionary);
4396 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004397 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004398 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004399 }
4400
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004401 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004402 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004403
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004404 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004405 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004406 Object* callback = result.GetCallbackObject();
4407 // To be compatible with Safari we do not change the value on API objects
4408 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4409 // the value.
4410 if (callback->IsAccessorInfo()) {
4411 return isolate->heap()->undefined_value();
4412 }
4413 // Avoid redefining foreign callback as data property, just use the stored
4414 // setter to update the value instead.
4415 // TODO(mstarzinger): So far this only works if property attributes don't
4416 // change, this should be fixed once we cleanup the underlying code.
4417 if (callback->IsForeign() && result.GetAttributes() == attr) {
4418 return js_object->SetPropertyWithCallback(callback,
4419 *name,
4420 *obj_value,
4421 result.holder(),
4422 kStrictMode);
4423 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004424 }
4425
ager@chromium.org5c838252010-02-19 08:53:10 +00004426 // Take special care when attributes are different and there is already
4427 // a property. For simplicity we normalize the property which enables us
4428 // to not worry about changing the instance_descriptor and creating a new
4429 // map. The current version of SetObjectProperty does not handle attributes
4430 // correctly in the case where a property is a field and is reset with
4431 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004432 if (result.IsProperty() &&
4433 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004434 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004435 if (js_object->IsJSGlobalProxy()) {
4436 // Since the result is a property, the prototype will exist so
4437 // we don't have to check for null.
4438 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004439 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004440 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004441 // Use IgnoreAttributes version since a readonly property may be
4442 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004443 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4444 *obj_value,
4445 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004446 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004447
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004448 return Runtime::ForceSetObjectProperty(isolate,
4449 js_object,
4450 name,
4451 obj_value,
4452 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004453}
4454
4455
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004456// Special case for elements if any of the flags are true.
4457// If elements are in fast case we always implicitly assume that:
4458// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4459static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4460 Handle<JSObject> js_object,
4461 uint32_t index,
4462 Handle<Object> value,
4463 PropertyAttributes attr) {
4464 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004465 Handle<SeededNumberDictionary> dictionary =
4466 JSObject::NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004467 // Make sure that we never go back to fast case.
4468 dictionary->set_requires_slow_elements();
4469 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004470 Handle<SeededNumberDictionary> extended_dictionary =
4471 SeededNumberDictionary::Set(dictionary, index, value, details);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004472 if (*extended_dictionary != *dictionary) {
4473 js_object->set_elements(*extended_dictionary);
4474 }
4475 return *value;
4476}
4477
4478
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004479MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4480 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004481 Handle<Object> key,
4482 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004483 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004484 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004485 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004486
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004487 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004488 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004490 isolate->factory()->NewTypeError("non_object_property_store",
4491 HandleVector(args, 2));
4492 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004493 }
4494
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004495 if (object->IsJSProxy()) {
4496 bool has_pending_exception = false;
4497 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4498 if (has_pending_exception) return Failure::Exception();
4499 return JSProxy::cast(*object)->SetProperty(
4500 String::cast(*name), *value, attr, strict_mode);
4501 }
4502
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 // If the object isn't a JavaScript object, we ignore the store.
4504 if (!object->IsJSObject()) return *value;
4505
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004506 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4507
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004508 // Check if the given key is an array index.
4509 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004510 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004511 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4512 // of a string using [] notation. We need to support this too in
4513 // JavaScript.
4514 // In the case of a String object we just need to redirect the assignment to
4515 // the underlying string if the index is in range. Since the underlying
4516 // string does nothing with the assignment then we can ignore such
4517 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004518 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004519 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004520 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004522 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4523 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4524 }
4525
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004526 Handle<Object> result =
4527 JSObject::SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004528 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529 return *value;
4530 }
4531
4532 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004533 Handle<Object> result;
4534 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004535 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4536 return NormalizeObjectSetElement(isolate,
4537 js_object,
4538 index,
4539 value,
4540 attr);
4541 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004542 result =
4543 JSObject::SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004544 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004545 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004546 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004547 result = JSReceiver::SetProperty(
4548 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004549 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004550 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004551 return *value;
4552 }
4553
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004554 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004555 bool has_pending_exception = false;
4556 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4557 if (has_pending_exception) return Failure::Exception();
4558 Handle<String> name = Handle<String>::cast(converted);
4559
4560 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004561 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004562 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004563 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004564 }
4565}
4566
4567
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004568MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4569 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004570 Handle<Object> key,
4571 Handle<Object> value,
4572 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004573 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004574
4575 // Check if the given key is an array index.
4576 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004577 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004578 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4579 // of a string using [] notation. We need to support this too in
4580 // JavaScript.
4581 // In the case of a String object we just need to redirect the assignment to
4582 // the underlying string if the index is in range. Since the underlying
4583 // string does nothing with the assignment then we can ignore such
4584 // assignments.
4585 if (js_object->IsStringObjectWithCharacterAt(index)) {
4586 return *value;
4587 }
4588
whesse@chromium.org7b260152011-06-20 15:33:18 +00004589 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004590 }
4591
4592 if (key->IsString()) {
4593 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004594 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004595 } else {
4596 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004597 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004598 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4599 *value,
4600 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004601 }
4602 }
4603
4604 // Call-back into JavaScript to convert the key to a string.
4605 bool has_pending_exception = false;
4606 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4607 if (has_pending_exception) return Failure::Exception();
4608 Handle<String> name = Handle<String>::cast(converted);
4609
4610 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004611 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004612 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004613 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004614 }
4615}
4616
4617
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004618MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004619 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004620 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004621 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004622
4623 // Check if the given key is an array index.
4624 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004625 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004626 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4627 // characters of a string using [] notation. In the case of a
4628 // String object we just need to redirect the deletion to the
4629 // underlying string if the index is in range. Since the
4630 // underlying string does nothing with the deletion, we can ignore
4631 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004632 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004633 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004634 }
4635
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004636 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004637 }
4638
4639 Handle<String> key_string;
4640 if (key->IsString()) {
4641 key_string = Handle<String>::cast(key);
4642 } else {
4643 // Call-back into JavaScript to convert the key to a string.
4644 bool has_pending_exception = false;
4645 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4646 if (has_pending_exception) return Failure::Exception();
4647 key_string = Handle<String>::cast(converted);
4648 }
4649
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004650 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004651 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004652}
4653
4654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004655RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004656 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004657 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004658
4659 Handle<Object> object = args.at<Object>(0);
4660 Handle<Object> key = args.at<Object>(1);
4661 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004662 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004663 RUNTIME_ASSERT(
4664 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004665 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004666 PropertyAttributes attributes =
4667 static_cast<PropertyAttributes>(unchecked_attributes);
4668
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004669 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004670 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004671 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4672 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004673 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004674
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004675 return Runtime::SetObjectProperty(isolate,
4676 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004677 key,
4678 value,
4679 attributes,
4680 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681}
4682
4683
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004684RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4685 NoHandleAllocation ha;
4686 RUNTIME_ASSERT(args.length() == 1);
4687 Handle<Object> object = args.at<Object>(0);
4688 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4689}
4690
4691
4692RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4693 NoHandleAllocation ha;
4694 RUNTIME_ASSERT(args.length() == 1);
4695 Handle<Object> object = args.at<Object>(0);
4696 return TransitionElements(object, FAST_ELEMENTS, isolate);
4697}
4698
4699
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004700// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004701// This is used to decide if we should transform null and undefined
4702// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004703RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004704 NoHandleAllocation ha;
4705 RUNTIME_ASSERT(args.length() == 1);
4706
4707 Handle<Object> object = args.at<Object>(0);
4708
4709 if (object->IsJSFunction()) {
4710 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004711 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004712 }
4713 return isolate->heap()->undefined_value();
4714}
4715
4716
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004717RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4718 RUNTIME_ASSERT(args.length() == 5);
4719 CONVERT_ARG_CHECKED(JSObject, object, 0);
4720 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4721 Handle<Object> value = args.at<Object>(2);
4722 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4723 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4724 HandleScope scope;
4725
4726 Object* raw_boilerplate_object = literals->get(literal_index);
4727 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4728#if DEBUG
4729 ElementsKind elements_kind = object->GetElementsKind();
4730#endif
4731 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4732 // Smis should never trigger transitions.
4733 ASSERT(!value->IsSmi());
4734
4735 if (value->IsNumber()) {
4736 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004737 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4738 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004739 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4740 FixedDoubleArray* double_array =
4741 FixedDoubleArray::cast(object->elements());
4742 HeapNumber* number = HeapNumber::cast(*value);
4743 double_array->set(store_index, number->Number());
4744 } else {
4745 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4746 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004747 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4748 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004749 FixedArray* object_array =
4750 FixedArray::cast(object->elements());
4751 object_array->set(store_index, *value);
4752 }
4753 return *object;
4754}
4755
4756
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757// Set a local property, even if it is READ_ONLY. If the property does not
4758// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004759RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004760 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004761 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 CONVERT_CHECKED(JSObject, object, args[0]);
4763 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004764 // Compute attributes.
4765 PropertyAttributes attributes = NONE;
4766 if (args.length() == 4) {
4767 CONVERT_CHECKED(Smi, value_obj, args[3]);
4768 int unchecked_value = value_obj->value();
4769 // Only attribute bits should be set.
4770 RUNTIME_ASSERT(
4771 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4772 attributes = static_cast<PropertyAttributes>(unchecked_value);
4773 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004775 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004776 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004777}
4778
4779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004780RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004782 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004783
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004784 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785 CONVERT_CHECKED(String, key, args[1]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004786 CONVERT_STRICT_MODE_ARG(strict_mode, 2);
4787 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004788 ? JSReceiver::STRICT_DELETION
4789 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790}
4791
4792
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004793static Object* HasLocalPropertyImplementation(Isolate* isolate,
4794 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004795 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004796 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004797 // Handle hidden prototypes. If there's a hidden prototype above this thing
4798 // then we have to check it for properties, because they are supposed to
4799 // look like they are on this object.
4800 Handle<Object> proto(object->GetPrototype());
4801 if (proto->IsJSObject() &&
4802 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004803 return HasLocalPropertyImplementation(isolate,
4804 Handle<JSObject>::cast(proto),
4805 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004806 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004807 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004808}
4809
4810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004811RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004812 NoHandleAllocation ha;
4813 ASSERT(args.length() == 2);
4814 CONVERT_CHECKED(String, key, args[1]);
4815
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004816 uint32_t index;
4817 const bool key_is_array_index = key->AsArrayIndex(&index);
4818
ager@chromium.org9085a012009-05-11 19:22:57 +00004819 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004820 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004821 if (obj->IsJSObject()) {
4822 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004823 // Fast case: either the key is a real named property or it is not
4824 // an array index and there are no interceptors or hidden
4825 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004826 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004827 Map* map = object->map();
4828 if (!key_is_array_index &&
4829 !map->has_named_interceptor() &&
4830 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4831 return isolate->heap()->false_value();
4832 }
4833 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004834 HandleScope scope(isolate);
4835 return HasLocalPropertyImplementation(isolate,
4836 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004837 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004838 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004839 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004840 String* string = String::cast(obj);
4841 if (index < static_cast<uint32_t>(string->length())) {
4842 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843 }
4844 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004845 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004846}
4847
4848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004849RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004850 NoHandleAllocation na;
4851 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004852 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4853 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004854
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004855 bool result = receiver->HasProperty(key);
4856 if (isolate->has_pending_exception()) return Failure::Exception();
4857 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004858}
4859
4860
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004861RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004862 NoHandleAllocation na;
4863 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004864 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4865 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004867 bool result = receiver->HasElement(index->value());
4868 if (isolate->has_pending_exception()) return Failure::Exception();
4869 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004870}
4871
4872
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004873RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004874 NoHandleAllocation ha;
4875 ASSERT(args.length() == 2);
4876
4877 CONVERT_CHECKED(JSObject, object, args[0]);
4878 CONVERT_CHECKED(String, key, args[1]);
4879
4880 uint32_t index;
4881 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004882 JSObject::LocalElementType type = object->HasLocalElement(index);
4883 switch (type) {
4884 case JSObject::UNDEFINED_ELEMENT:
4885 case JSObject::STRING_CHARACTER_ELEMENT:
4886 return isolate->heap()->false_value();
4887 case JSObject::INTERCEPTED_ELEMENT:
4888 case JSObject::FAST_ELEMENT:
4889 return isolate->heap()->true_value();
4890 case JSObject::DICTIONARY_ELEMENT: {
4891 if (object->IsJSGlobalProxy()) {
4892 Object* proto = object->GetPrototype();
4893 if (proto->IsNull()) {
4894 return isolate->heap()->false_value();
4895 }
4896 ASSERT(proto->IsJSGlobalObject());
4897 object = JSObject::cast(proto);
4898 }
4899 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004900 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004901 if (elements->map() ==
4902 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004903 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004904 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004905 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004906 }
4907 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004908 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004909 PropertyDetails details = dictionary->DetailsAt(entry);
4910 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4911 }
4912 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004913 }
4914
ager@chromium.org870a0b62008-11-04 11:43:05 +00004915 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004916 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004917}
4918
4919
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004920RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004921 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004922 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004923 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4924 bool threw = false;
4925 Handle<JSArray> result = GetKeysFor(object, &threw);
4926 if (threw) return Failure::Exception();
4927 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004928}
4929
4930
4931// Returns either a FixedArray as Runtime_GetPropertyNames,
4932// or, if the given object has an enum cache that contains
4933// all enumerable properties of the object and its prototypes
4934// have none, the map of the object. This is used to speed up
4935// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004936RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004937 ASSERT(args.length() == 1);
4938
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004939 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004940
4941 if (raw_object->IsSimpleEnum()) return raw_object->map();
4942
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004943 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004944 Handle<JSReceiver> object(raw_object);
4945 bool threw = false;
4946 Handle<FixedArray> content =
4947 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4948 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004949
4950 // Test again, since cache may have been built by preceding call.
4951 if (object->IsSimpleEnum()) return object->map();
4952
4953 return *content;
4954}
4955
4956
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004957// Find the length of the prototype chain that is to to handled as one. If a
4958// prototype object is hidden it is to be viewed as part of the the object it
4959// is prototype for.
4960static int LocalPrototypeChainLength(JSObject* obj) {
4961 int count = 1;
4962 Object* proto = obj->GetPrototype();
4963 while (proto->IsJSObject() &&
4964 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4965 count++;
4966 proto = JSObject::cast(proto)->GetPrototype();
4967 }
4968 return count;
4969}
4970
4971
4972// Return the names of the local named properties.
4973// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004974RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004975 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004976 ASSERT(args.length() == 1);
4977 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004978 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004979 }
4980 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4981
4982 // Skip the global proxy as it has no properties and always delegates to the
4983 // real global object.
4984 if (obj->IsJSGlobalProxy()) {
4985 // Only collect names if access is permitted.
4986 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004987 !isolate->MayNamedAccess(*obj,
4988 isolate->heap()->undefined_value(),
4989 v8::ACCESS_KEYS)) {
4990 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4991 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004992 }
4993 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4994 }
4995
4996 // Find the number of objects making up this.
4997 int length = LocalPrototypeChainLength(*obj);
4998
4999 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005000 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005001 int total_property_count = 0;
5002 Handle<JSObject> jsproto = obj;
5003 for (int i = 0; i < length; i++) {
5004 // Only collect names if access is permitted.
5005 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005006 !isolate->MayNamedAccess(*jsproto,
5007 isolate->heap()->undefined_value(),
5008 v8::ACCESS_KEYS)) {
5009 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
5010 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005011 }
5012 int n;
5013 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
5014 local_property_count[i] = n;
5015 total_property_count += n;
5016 if (i < length - 1) {
5017 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5018 }
5019 }
5020
5021 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005022 Handle<FixedArray> names =
5023 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005024
5025 // Get the property names.
5026 jsproto = obj;
5027 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005028 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005029 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005030 jsproto->GetLocalPropertyNames(*names, next_copy_index);
5031 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005032 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005033 proto_with_hidden_properties++;
5034 }
5035 if (i < length - 1) {
5036 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5037 }
5038 }
5039
5040 // Filter out name of hidden propeties object.
5041 if (proto_with_hidden_properties > 0) {
5042 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005043 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005044 names->length() - proto_with_hidden_properties);
5045 int dest_pos = 0;
5046 for (int i = 0; i < total_property_count; i++) {
5047 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005048 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005049 continue;
5050 }
5051 names->set(dest_pos++, name);
5052 }
5053 }
5054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005055 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005056}
5057
5058
5059// Return the names of the local indexed properties.
5060// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005061RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005062 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005063 ASSERT(args.length() == 1);
5064 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005065 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005066 }
5067 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5068
5069 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005070 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005071 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005072 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005073}
5074
5075
5076// Return information on whether an object has a named or indexed interceptor.
5077// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005078RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005080 ASSERT(args.length() == 1);
5081 if (!args[0]->IsJSObject()) {
5082 return Smi::FromInt(0);
5083 }
5084 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5085
5086 int result = 0;
5087 if (obj->HasNamedInterceptor()) result |= 2;
5088 if (obj->HasIndexedInterceptor()) result |= 1;
5089
5090 return Smi::FromInt(result);
5091}
5092
5093
5094// Return property names from named interceptor.
5095// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005096RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005097 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005098 ASSERT(args.length() == 1);
5099 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5100
5101 if (obj->HasNamedInterceptor()) {
5102 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5103 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5104 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005105 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005106}
5107
5108
5109// Return element names from indexed interceptor.
5110// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005111RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005112 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005113 ASSERT(args.length() == 1);
5114 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5115
5116 if (obj->HasIndexedInterceptor()) {
5117 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5118 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5119 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005120 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005121}
5122
5123
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005124RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005125 ASSERT_EQ(args.length(), 1);
5126 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005127 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005128 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005129
5130 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005131 // Do access checks before going to the global object.
5132 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005133 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005134 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005135 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5136 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005137 }
5138
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005139 Handle<Object> proto(object->GetPrototype());
5140 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005141 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005142 object = Handle<JSObject>::cast(proto);
5143 }
5144
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005145 bool threw = false;
5146 Handle<FixedArray> contents =
5147 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5148 if (threw) return Failure::Exception();
5149
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005150 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5151 // property array and since the result is mutable we have to create
5152 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005153 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005154 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005155 for (int i = 0; i < length; i++) {
5156 Object* entry = contents->get(i);
5157 if (entry->IsString()) {
5158 copy->set(i, entry);
5159 } else {
5160 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005161 HandleScope scope(isolate);
5162 Handle<Object> entry_handle(entry, isolate);
5163 Handle<Object> entry_str =
5164 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005165 copy->set(i, *entry_str);
5166 }
5167 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005168 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005169}
5170
5171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005172RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005173 NoHandleAllocation ha;
5174 ASSERT(args.length() == 1);
5175
5176 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005177 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005178 it.AdvanceToArgumentsFrame();
5179 JavaScriptFrame* frame = it.frame();
5180
5181 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005182 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005183
5184 // Try to convert the key to an index. If successful and within
5185 // index return the the argument from the frame.
5186 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005187 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005188 return frame->GetParameter(index);
5189 }
5190
5191 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005192 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005193 bool exception = false;
5194 Handle<Object> converted =
5195 Execution::ToString(args.at<Object>(0), &exception);
5196 if (exception) return Failure::Exception();
5197 Handle<String> key = Handle<String>::cast(converted);
5198
5199 // Try to convert the string key into an array index.
5200 if (key->AsArrayIndex(&index)) {
5201 if (index < n) {
5202 return frame->GetParameter(index);
5203 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005204 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005205 }
5206 }
5207
5208 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005209 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5210 if (key->Equals(isolate->heap()->callee_symbol())) {
5211 Object* function = frame->function();
5212 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005213 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005214 return isolate->Throw(*isolate->factory()->NewTypeError(
5215 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5216 }
5217 return function;
5218 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005219
5220 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005221 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005222}
5223
5224
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005225RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005226 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005227 Object* object = args[0];
5228 return (object->IsJSObject() && !object->IsGlobalObject())
5229 ? JSObject::cast(object)->TransformToFastProperties(0)
5230 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005231}
5232
5233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005234RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005235 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005236 Object* obj = args[0];
5237 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5238 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5239 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005240}
5241
5242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005243RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005244 NoHandleAllocation ha;
5245 ASSERT(args.length() == 1);
5246
5247 return args[0]->ToBoolean();
5248}
5249
5250
5251// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5252// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005253RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005254 NoHandleAllocation ha;
5255
5256 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005257 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005258 HeapObject* heap_obj = HeapObject::cast(obj);
5259
5260 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005261 if (heap_obj->map()->is_undetectable()) {
5262 return isolate->heap()->undefined_symbol();
5263 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005264
5265 InstanceType instance_type = heap_obj->map()->instance_type();
5266 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005267 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005268 }
5269
5270 switch (instance_type) {
5271 case ODDBALL_TYPE:
5272 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005273 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005274 }
5275 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005276 return FLAG_harmony_typeof
5277 ? isolate->heap()->null_symbol()
5278 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005279 }
5280 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005281 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005282 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005283 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005284 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005285 default:
5286 // For any kind of object not handled above, the spec rule for
5287 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005288 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005289 }
5290}
5291
5292
lrn@chromium.org25156de2010-04-06 13:10:27 +00005293static bool AreDigits(const char*s, int from, int to) {
5294 for (int i = from; i < to; i++) {
5295 if (s[i] < '0' || s[i] > '9') return false;
5296 }
5297
5298 return true;
5299}
5300
5301
5302static int ParseDecimalInteger(const char*s, int from, int to) {
5303 ASSERT(to - from < 10); // Overflow is not possible.
5304 ASSERT(from < to);
5305 int d = s[from] - '0';
5306
5307 for (int i = from + 1; i < to; i++) {
5308 d = 10 * d + (s[i] - '0');
5309 }
5310
5311 return d;
5312}
5313
5314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005315RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005316 NoHandleAllocation ha;
5317 ASSERT(args.length() == 1);
5318 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005319 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005320
5321 // Fast case: short integer or some sorts of junk values.
5322 int len = subject->length();
5323 if (subject->IsSeqAsciiString()) {
5324 if (len == 0) return Smi::FromInt(0);
5325
5326 char const* data = SeqAsciiString::cast(subject)->GetChars();
5327 bool minus = (data[0] == '-');
5328 int start_pos = (minus ? 1 : 0);
5329
5330 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005331 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005332 } else if (data[start_pos] > '9') {
5333 // Fast check for a junk value. A valid string may start from a
5334 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5335 // the 'I' character ('Infinity'). All of that have codes not greater than
5336 // '9' except 'I'.
5337 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005338 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005339 }
5340 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5341 // The maximal/minimal smi has 10 digits. If the string has less digits we
5342 // know it will fit into the smi-data type.
5343 int d = ParseDecimalInteger(data, start_pos, len);
5344 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005345 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005346 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005347 } else if (!subject->HasHashCode() &&
5348 len <= String::kMaxArrayIndexSize &&
5349 (len == 1 || data[0] != '0')) {
5350 // String hash is not calculated yet but all the data are present.
5351 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005352 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005353#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005354 subject->Hash(); // Force hash calculation.
5355 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5356 static_cast<int>(hash));
5357#endif
5358 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005359 }
5360 return Smi::FromInt(d);
5361 }
5362 }
5363
5364 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005365 return isolate->heap()->NumberFromDouble(
5366 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005367}
5368
5369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005370RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005371 NoHandleAllocation ha;
5372 ASSERT(args.length() == 1);
5373
5374 CONVERT_CHECKED(JSArray, codes, args[0]);
5375 int length = Smi::cast(codes->length())->value();
5376
5377 // Check if the string can be ASCII.
5378 int i;
5379 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005380 Object* element;
5381 { MaybeObject* maybe_element = codes->GetElement(i);
5382 // We probably can't get an exception here, but just in order to enforce
5383 // the checking of inputs in the runtime calls we check here.
5384 if (!maybe_element->ToObject(&element)) return maybe_element;
5385 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005386 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5387 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5388 break;
5389 }
5390
lrn@chromium.org303ada72010-10-27 09:33:13 +00005391 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005392 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005393 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005394 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005395 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005396 }
5397
lrn@chromium.org303ada72010-10-27 09:33:13 +00005398 Object* object = NULL;
5399 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005400 String* result = String::cast(object);
5401 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005402 Object* element;
5403 { MaybeObject* maybe_element = codes->GetElement(i);
5404 if (!maybe_element->ToObject(&element)) return maybe_element;
5405 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005406 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005407 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005408 }
5409 return result;
5410}
5411
5412
5413// kNotEscaped is generated by the following:
5414//
5415// #!/bin/perl
5416// for (my $i = 0; $i < 256; $i++) {
5417// print "\n" if $i % 16 == 0;
5418// my $c = chr($i);
5419// my $escaped = 1;
5420// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5421// print $escaped ? "0, " : "1, ";
5422// }
5423
5424
5425static bool IsNotEscaped(uint16_t character) {
5426 // Only for 8 bit characters, the rest are always escaped (in a different way)
5427 ASSERT(character < 256);
5428 static const char kNotEscaped[256] = {
5429 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5430 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5431 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5432 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5433 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5434 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5435 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5436 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5438 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5440 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5441 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5444 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5445 };
5446 return kNotEscaped[character] != 0;
5447}
5448
5449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005450RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005451 const char hex_chars[] = "0123456789ABCDEF";
5452 NoHandleAllocation ha;
5453 ASSERT(args.length() == 1);
5454 CONVERT_CHECKED(String, source, args[0]);
5455
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005456 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005457
5458 int escaped_length = 0;
5459 int length = source->length();
5460 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005461 Access<StringInputBuffer> buffer(
5462 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005463 buffer->Reset(source);
5464 while (buffer->has_more()) {
5465 uint16_t character = buffer->GetNext();
5466 if (character >= 256) {
5467 escaped_length += 6;
5468 } else if (IsNotEscaped(character)) {
5469 escaped_length++;
5470 } else {
5471 escaped_length += 3;
5472 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005473 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005474 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005475 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005476 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005477 return Failure::OutOfMemoryException();
5478 }
5479 }
5480 }
5481 // No length change implies no change. Return original string if no change.
5482 if (escaped_length == length) {
5483 return source;
5484 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005485 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005486 { MaybeObject* maybe_o =
5487 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005488 if (!maybe_o->ToObject(&o)) return maybe_o;
5489 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005490 String* destination = String::cast(o);
5491 int dest_position = 0;
5492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005493 Access<StringInputBuffer> buffer(
5494 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005495 buffer->Rewind();
5496 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005497 uint16_t chr = buffer->GetNext();
5498 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005499 destination->Set(dest_position, '%');
5500 destination->Set(dest_position+1, 'u');
5501 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5502 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5503 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5504 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005505 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005506 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005507 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005508 dest_position++;
5509 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005510 destination->Set(dest_position, '%');
5511 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5512 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005513 dest_position += 3;
5514 }
5515 }
5516 return destination;
5517}
5518
5519
5520static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5521 static const signed char kHexValue['g'] = {
5522 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5523 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5524 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5525 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5526 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5527 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5528 -1, 10, 11, 12, 13, 14, 15 };
5529
5530 if (character1 > 'f') return -1;
5531 int hi = kHexValue[character1];
5532 if (hi == -1) return -1;
5533 if (character2 > 'f') return -1;
5534 int lo = kHexValue[character2];
5535 if (lo == -1) return -1;
5536 return (hi << 4) + lo;
5537}
5538
5539
ager@chromium.org870a0b62008-11-04 11:43:05 +00005540static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005541 int i,
5542 int length,
5543 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005544 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005545 int32_t hi = 0;
5546 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005547 if (character == '%' &&
5548 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005549 source->Get(i + 1) == 'u' &&
5550 (hi = TwoDigitHex(source->Get(i + 2),
5551 source->Get(i + 3))) != -1 &&
5552 (lo = TwoDigitHex(source->Get(i + 4),
5553 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005554 *step = 6;
5555 return (hi << 8) + lo;
5556 } else if (character == '%' &&
5557 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005558 (lo = TwoDigitHex(source->Get(i + 1),
5559 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005560 *step = 3;
5561 return lo;
5562 } else {
5563 *step = 1;
5564 return character;
5565 }
5566}
5567
5568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005569RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005570 NoHandleAllocation ha;
5571 ASSERT(args.length() == 1);
5572 CONVERT_CHECKED(String, source, args[0]);
5573
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005574 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005575
5576 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005577 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005578
5579 int unescaped_length = 0;
5580 for (int i = 0; i < length; unescaped_length++) {
5581 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005582 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005583 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005584 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005585 i += step;
5586 }
5587
5588 // No length change implies no change. Return original string if no change.
5589 if (unescaped_length == length)
5590 return source;
5591
lrn@chromium.org303ada72010-10-27 09:33:13 +00005592 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005593 { MaybeObject* maybe_o =
5594 ascii ?
5595 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5596 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005597 if (!maybe_o->ToObject(&o)) return maybe_o;
5598 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005599 String* destination = String::cast(o);
5600
5601 int dest_position = 0;
5602 for (int i = 0; i < length; dest_position++) {
5603 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005604 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005605 i += step;
5606 }
5607 return destination;
5608}
5609
5610
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005611static const unsigned int kQuoteTableLength = 128u;
5612
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005613static const int kJsonQuotesCharactersPerEntry = 8;
5614static const char* const JsonQuotes =
5615 "\\u0000 \\u0001 \\u0002 \\u0003 "
5616 "\\u0004 \\u0005 \\u0006 \\u0007 "
5617 "\\b \\t \\n \\u000b "
5618 "\\f \\r \\u000e \\u000f "
5619 "\\u0010 \\u0011 \\u0012 \\u0013 "
5620 "\\u0014 \\u0015 \\u0016 \\u0017 "
5621 "\\u0018 \\u0019 \\u001a \\u001b "
5622 "\\u001c \\u001d \\u001e \\u001f "
5623 " ! \\\" # "
5624 "$ % & ' "
5625 "( ) * + "
5626 ", - . / "
5627 "0 1 2 3 "
5628 "4 5 6 7 "
5629 "8 9 : ; "
5630 "< = > ? "
5631 "@ A B C "
5632 "D E F G "
5633 "H I J K "
5634 "L M N O "
5635 "P Q R S "
5636 "T U V W "
5637 "X Y Z [ "
5638 "\\\\ ] ^ _ "
5639 "` a b c "
5640 "d e f g "
5641 "h i j k "
5642 "l m n o "
5643 "p q r s "
5644 "t u v w "
5645 "x y z { "
5646 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005647
5648
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005649// For a string that is less than 32k characters it should always be
5650// possible to allocate it in new space.
5651static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5652
5653
5654// Doing JSON quoting cannot make the string more than this many times larger.
5655static const int kJsonQuoteWorstCaseBlowup = 6;
5656
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005657static const int kSpaceForQuotesAndComma = 3;
5658static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005659
5660// Covers the entire ASCII range (all other characters are unchanged by JSON
5661// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005662static const byte JsonQuoteLengths[kQuoteTableLength] = {
5663 6, 6, 6, 6, 6, 6, 6, 6,
5664 2, 2, 2, 6, 2, 2, 6, 6,
5665 6, 6, 6, 6, 6, 6, 6, 6,
5666 6, 6, 6, 6, 6, 6, 6, 6,
5667 1, 1, 2, 1, 1, 1, 1, 1,
5668 1, 1, 1, 1, 1, 1, 1, 1,
5669 1, 1, 1, 1, 1, 1, 1, 1,
5670 1, 1, 1, 1, 1, 1, 1, 1,
5671 1, 1, 1, 1, 1, 1, 1, 1,
5672 1, 1, 1, 1, 1, 1, 1, 1,
5673 1, 1, 1, 1, 1, 1, 1, 1,
5674 1, 1, 1, 1, 2, 1, 1, 1,
5675 1, 1, 1, 1, 1, 1, 1, 1,
5676 1, 1, 1, 1, 1, 1, 1, 1,
5677 1, 1, 1, 1, 1, 1, 1, 1,
5678 1, 1, 1, 1, 1, 1, 1, 1,
5679};
5680
5681
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005682template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005683MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005684
5685
5686template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005687MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5688 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005689}
5690
5691
5692template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005693MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5694 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005695}
5696
5697
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005698template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005699static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5700 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005701 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005702 const Char* read_cursor = characters.start();
5703 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005704 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005705 int quoted_length = kSpaceForQuotes;
5706 while (read_cursor < end) {
5707 Char c = *(read_cursor++);
5708 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5709 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005710 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005711 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005712 }
5713 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005714 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5715 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005716 Object* new_object;
5717 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005718 return new_alloc;
5719 }
5720 StringType* new_string = StringType::cast(new_object);
5721
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005722 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005723 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005724 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005725 *(write_cursor++) = '"';
5726
5727 read_cursor = characters.start();
5728 while (read_cursor < end) {
5729 Char c = *(read_cursor++);
5730 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5731 *(write_cursor++) = c;
5732 } else {
5733 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5734 const char* replacement = JsonQuotes +
5735 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5736 for (int i = 0; i < len; i++) {
5737 *write_cursor++ = *replacement++;
5738 }
5739 }
5740 }
5741 *(write_cursor++) = '"';
5742 return new_string;
5743}
5744
5745
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005746template <typename SinkChar, typename SourceChar>
5747static inline SinkChar* WriteQuoteJsonString(
5748 Isolate* isolate,
5749 SinkChar* write_cursor,
5750 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005751 // SinkChar is only char if SourceChar is guaranteed to be char.
5752 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005753 const SourceChar* read_cursor = characters.start();
5754 const SourceChar* end = read_cursor + characters.length();
5755 *(write_cursor++) = '"';
5756 while (read_cursor < end) {
5757 SourceChar c = *(read_cursor++);
5758 if (sizeof(SourceChar) > 1u &&
5759 static_cast<unsigned>(c) >= kQuoteTableLength) {
5760 *(write_cursor++) = static_cast<SinkChar>(c);
5761 } else {
5762 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5763 const char* replacement = JsonQuotes +
5764 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5765 write_cursor[0] = replacement[0];
5766 if (len > 1) {
5767 write_cursor[1] = replacement[1];
5768 if (len > 2) {
5769 ASSERT(len == 6);
5770 write_cursor[2] = replacement[2];
5771 write_cursor[3] = replacement[3];
5772 write_cursor[4] = replacement[4];
5773 write_cursor[5] = replacement[5];
5774 }
5775 }
5776 write_cursor += len;
5777 }
5778 }
5779 *(write_cursor++) = '"';
5780 return write_cursor;
5781}
5782
5783
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005784template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005785static MaybeObject* QuoteJsonString(Isolate* isolate,
5786 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005787 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005788 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005789 int worst_case_length =
5790 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005791 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005792 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005793 }
5794
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005795 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5796 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005797 Object* new_object;
5798 if (!new_alloc->ToObject(&new_object)) {
5799 return new_alloc;
5800 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005801 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005802 // Even if our string is small enough to fit in new space we still have to
5803 // handle it being allocated in old space as may happen in the third
5804 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5805 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005806 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005807 }
5808 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005809 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005810
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005811 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005812 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005813 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005814 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5815 write_cursor,
5816 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005817 int final_length = static_cast<int>(
5818 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005819 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005820 isolate->heap()->new_space()->
5821 template ShrinkStringAtAllocationBoundary<StringType>(
5822 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005823 return new_string;
5824}
5825
5826
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005827RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005828 NoHandleAllocation ha;
5829 CONVERT_CHECKED(String, str, args[0]);
5830 if (!str->IsFlat()) {
5831 MaybeObject* try_flatten = str->TryFlatten();
5832 Object* flat;
5833 if (!try_flatten->ToObject(&flat)) {
5834 return try_flatten;
5835 }
5836 str = String::cast(flat);
5837 ASSERT(str->IsFlat());
5838 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005839 String::FlatContent flat = str->GetFlatContent();
5840 ASSERT(flat.IsFlat());
5841 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005842 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005843 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005844 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005845 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005846 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005847 }
5848}
5849
5850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005851RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005852 NoHandleAllocation ha;
5853 CONVERT_CHECKED(String, str, args[0]);
5854 if (!str->IsFlat()) {
5855 MaybeObject* try_flatten = str->TryFlatten();
5856 Object* flat;
5857 if (!try_flatten->ToObject(&flat)) {
5858 return try_flatten;
5859 }
5860 str = String::cast(flat);
5861 ASSERT(str->IsFlat());
5862 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005863 String::FlatContent flat = str->GetFlatContent();
5864 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005865 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005866 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005867 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005868 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005869 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005870 }
5871}
5872
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005873
5874template <typename Char, typename StringType>
5875static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5876 FixedArray* array,
5877 int worst_case_length) {
5878 int length = array->length();
5879
5880 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5881 worst_case_length);
5882 Object* new_object;
5883 if (!new_alloc->ToObject(&new_object)) {
5884 return new_alloc;
5885 }
5886 if (!isolate->heap()->new_space()->Contains(new_object)) {
5887 // Even if our string is small enough to fit in new space we still have to
5888 // handle it being allocated in old space as may happen in the third
5889 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5890 // CEntryStub::GenerateCore.
5891 return isolate->heap()->undefined_value();
5892 }
5893 AssertNoAllocation no_gc;
5894 StringType* new_string = StringType::cast(new_object);
5895 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5896
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005897 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005898 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005899 *(write_cursor++) = '[';
5900 for (int i = 0; i < length; i++) {
5901 if (i != 0) *(write_cursor++) = ',';
5902 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005903 String::FlatContent content = str->GetFlatContent();
5904 ASSERT(content.IsFlat());
5905 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005906 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5907 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005908 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005909 } else {
5910 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5911 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005912 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005913 }
5914 }
5915 *(write_cursor++) = ']';
5916
5917 int final_length = static_cast<int>(
5918 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005919 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005920 isolate->heap()->new_space()->
5921 template ShrinkStringAtAllocationBoundary<StringType>(
5922 new_string, final_length);
5923 return new_string;
5924}
5925
5926
5927RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5928 NoHandleAllocation ha;
5929 ASSERT(args.length() == 1);
5930 CONVERT_CHECKED(JSArray, array, args[0]);
5931
5932 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5933 FixedArray* elements = FixedArray::cast(array->elements());
5934 int n = elements->length();
5935 bool ascii = true;
5936 int total_length = 0;
5937
5938 for (int i = 0; i < n; i++) {
5939 Object* elt = elements->get(i);
5940 if (!elt->IsString()) return isolate->heap()->undefined_value();
5941 String* element = String::cast(elt);
5942 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5943 total_length += element->length();
5944 if (ascii && element->IsTwoByteRepresentation()) {
5945 ascii = false;
5946 }
5947 }
5948
5949 int worst_case_length =
5950 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5951 + total_length * kJsonQuoteWorstCaseBlowup;
5952
5953 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5954 return isolate->heap()->undefined_value();
5955 }
5956
5957 if (ascii) {
5958 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5959 elements,
5960 worst_case_length);
5961 } else {
5962 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5963 elements,
5964 worst_case_length);
5965 }
5966}
5967
5968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005969RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005970 NoHandleAllocation ha;
5971
5972 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005973 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005975 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005976
lrn@chromium.org25156de2010-04-06 13:10:27 +00005977 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005978 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005979 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005980}
5981
5982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005983RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005984 NoHandleAllocation ha;
5985 CONVERT_CHECKED(String, str, args[0]);
5986
5987 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005988 double value = StringToDouble(isolate->unicode_cache(),
5989 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990
5991 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005992 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005993}
5994
5995
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005996template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005997MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005998 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005999 String* s,
6000 int length,
6001 int input_string_length,
6002 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006003 // We try this twice, once with the assumption that the result is no longer
6004 // than the input and, if that assumption breaks, again with the exact
6005 // length. This may not be pretty, but it is nicer than what was here before
6006 // and I hereby claim my vaffel-is.
6007 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008 // Allocate the resulting string.
6009 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006010 // NOTE: This assumes that the upper/lower case of an ASCII
6011 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006012 // might break in the future if we implement more context and locale
6013 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006014 Object* o;
6015 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006016 ? isolate->heap()->AllocateRawAsciiString(length)
6017 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006018 if (!maybe_o->ToObject(&o)) return maybe_o;
6019 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 String* result = String::cast(o);
6021 bool has_changed_character = false;
6022
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006023 // Convert all characters to upper case, assuming that they will fit
6024 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006025 Access<StringInputBuffer> buffer(
6026 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006028 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006029 // We can assume that the string is not empty
6030 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006031 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006032 bool has_next = buffer->has_more();
6033 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006034 int char_length = mapping->get(current, next, chars);
6035 if (char_length == 0) {
6036 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006037 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 i++;
6039 } else if (char_length == 1) {
6040 // Common case: converting the letter resulted in one character.
6041 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006042 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006043 has_changed_character = true;
6044 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006045 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006046 // We've assumed that the result would be as long as the
6047 // input but here is a character that converts to several
6048 // characters. No matter, we calculate the exact length
6049 // of the result and try the whole thing again.
6050 //
6051 // Note that this leaves room for optimization. We could just
6052 // memcpy what we already have to the result string. Also,
6053 // the result string is the last object allocated we could
6054 // "realloc" it and probably, in the vast majority of cases,
6055 // extend the existing string to be able to hold the full
6056 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006057 int next_length = 0;
6058 if (has_next) {
6059 next_length = mapping->get(next, 0, chars);
6060 if (next_length == 0) next_length = 1;
6061 }
6062 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006063 while (buffer->has_more()) {
6064 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006065 // NOTE: we use 0 as the next character here because, while
6066 // the next character may affect what a character converts to,
6067 // it does not in any case affect the length of what it convert
6068 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006069 int char_length = mapping->get(current, 0, chars);
6070 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006071 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006072 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006073 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006074 return Failure::OutOfMemoryException();
6075 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006077 // Try again with the real length.
6078 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006079 } else {
6080 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006081 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006082 i++;
6083 }
6084 has_changed_character = true;
6085 }
6086 current = next;
6087 }
6088 if (has_changed_character) {
6089 return result;
6090 } else {
6091 // If we didn't actually change anything in doing the conversion
6092 // we simple return the result and let the converted string
6093 // become garbage; there is no reason to keep two identical strings
6094 // alive.
6095 return s;
6096 }
6097}
6098
6099
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006100namespace {
6101
lrn@chromium.org303ada72010-10-27 09:33:13 +00006102static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6103
6104
6105// Given a word and two range boundaries returns a word with high bit
6106// set in every byte iff the corresponding input byte was strictly in
6107// the range (m, n). All the other bits in the result are cleared.
6108// This function is only useful when it can be inlined and the
6109// boundaries are statically known.
6110// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006111// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006112static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006113 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006114 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6115 // Use strict inequalities since in edge cases the function could be
6116 // further simplified.
6117 ASSERT(0 < m && m < n && n < 0x7F);
6118 // Has high bit set in every w byte less than n.
6119 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6120 // Has high bit set in every w byte greater than m.
6121 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6122 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6123}
6124
6125
6126enum AsciiCaseConversion {
6127 ASCII_TO_LOWER,
6128 ASCII_TO_UPPER
6129};
6130
6131
6132template <AsciiCaseConversion dir>
6133struct FastAsciiConverter {
6134 static bool Convert(char* dst, char* src, int length) {
6135#ifdef DEBUG
6136 char* saved_dst = dst;
6137 char* saved_src = src;
6138#endif
6139 // We rely on the distance between upper and lower case letters
6140 // being a known power of 2.
6141 ASSERT('a' - 'A' == (1 << 5));
6142 // Boundaries for the range of input characters than require conversion.
6143 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6144 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6145 bool changed = false;
6146 char* const limit = src + length;
6147#ifdef V8_HOST_CAN_READ_UNALIGNED
6148 // Process the prefix of the input that requires no conversion one
6149 // (machine) word at a time.
6150 while (src <= limit - sizeof(uintptr_t)) {
6151 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6152 if (AsciiRangeMask(w, lo, hi) != 0) {
6153 changed = true;
6154 break;
6155 }
6156 *reinterpret_cast<uintptr_t*>(dst) = w;
6157 src += sizeof(uintptr_t);
6158 dst += sizeof(uintptr_t);
6159 }
6160 // Process the remainder of the input performing conversion when
6161 // required one word at a time.
6162 while (src <= limit - sizeof(uintptr_t)) {
6163 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6164 uintptr_t m = AsciiRangeMask(w, lo, hi);
6165 // The mask has high (7th) bit set in every byte that needs
6166 // conversion and we know that the distance between cases is
6167 // 1 << 5.
6168 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6169 src += sizeof(uintptr_t);
6170 dst += sizeof(uintptr_t);
6171 }
6172#endif
6173 // Process the last few bytes of the input (or the whole input if
6174 // unaligned access is not supported).
6175 while (src < limit) {
6176 char c = *src;
6177 if (lo < c && c < hi) {
6178 c ^= (1 << 5);
6179 changed = true;
6180 }
6181 *dst = c;
6182 ++src;
6183 ++dst;
6184 }
6185#ifdef DEBUG
6186 CheckConvert(saved_dst, saved_src, length, changed);
6187#endif
6188 return changed;
6189 }
6190
6191#ifdef DEBUG
6192 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6193 bool expected_changed = false;
6194 for (int i = 0; i < length; i++) {
6195 if (dst[i] == src[i]) continue;
6196 expected_changed = true;
6197 if (dir == ASCII_TO_LOWER) {
6198 ASSERT('A' <= src[i] && src[i] <= 'Z');
6199 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6200 } else {
6201 ASSERT(dir == ASCII_TO_UPPER);
6202 ASSERT('a' <= src[i] && src[i] <= 'z');
6203 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6204 }
6205 }
6206 ASSERT(expected_changed == changed);
6207 }
6208#endif
6209};
6210
6211
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006212struct ToLowerTraits {
6213 typedef unibrow::ToLowercase UnibrowConverter;
6214
lrn@chromium.org303ada72010-10-27 09:33:13 +00006215 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006216};
6217
6218
6219struct ToUpperTraits {
6220 typedef unibrow::ToUppercase UnibrowConverter;
6221
lrn@chromium.org303ada72010-10-27 09:33:13 +00006222 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006223};
6224
6225} // namespace
6226
6227
6228template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006229MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006230 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006231 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006232 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006233 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006234 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006235 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006236
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006237 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006238 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006239 if (length == 0) return s;
6240
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006241 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006242 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006243 // NOTE: This assumes that the upper/lower case of an ASCII
6244 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006245 // might break in the future if we implement more context and locale
6246 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006247 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006248 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006249 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006250 if (!maybe_o->ToObject(&o)) return maybe_o;
6251 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006252 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006253 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006254 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006255 return has_changed_character ? result : s;
6256 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006257
lrn@chromium.org303ada72010-10-27 09:33:13 +00006258 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006259 { MaybeObject* maybe_answer =
6260 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006261 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6262 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006263 if (answer->IsSmi()) {
6264 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006265 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 ConvertCaseHelper(isolate,
6267 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006268 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6269 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006270 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006271 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006272}
6273
6274
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006275RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006276 return ConvertCase<ToLowerTraits>(
6277 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006278}
6279
6280
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006281RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006282 return ConvertCase<ToUpperTraits>(
6283 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006284}
6285
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006286
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006287static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006288 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006289}
6290
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006292RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006293 NoHandleAllocation ha;
6294 ASSERT(args.length() == 3);
6295
6296 CONVERT_CHECKED(String, s, args[0]);
6297 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6298 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6299
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006300 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006301 int length = s->length();
6302
6303 int left = 0;
6304 if (trimLeft) {
6305 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6306 left++;
6307 }
6308 }
6309
6310 int right = length;
6311 if (trimRight) {
6312 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6313 right--;
6314 }
6315 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006316 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006317}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006318
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006320RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006321 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006322 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006323 CONVERT_ARG_CHECKED(String, subject, 0);
6324 CONVERT_ARG_CHECKED(String, pattern, 1);
6325 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6326
6327 int subject_length = subject->length();
6328 int pattern_length = pattern->length();
6329 RUNTIME_ASSERT(pattern_length > 0);
6330
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006331 if (limit == 0xffffffffu) {
6332 Handle<Object> cached_answer(StringSplitCache::Lookup(
6333 isolate->heap()->string_split_cache(),
6334 *subject,
6335 *pattern));
6336 if (*cached_answer != Smi::FromInt(0)) {
6337 Handle<JSArray> result =
6338 isolate->factory()->NewJSArrayWithElements(
6339 Handle<FixedArray>::cast(cached_answer));
6340 return *result;
6341 }
6342 }
6343
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006344 // The limit can be very large (0xffffffffu), but since the pattern
6345 // isn't empty, we can never create more parts than ~half the length
6346 // of the subject.
6347
6348 if (!subject->IsFlat()) FlattenString(subject);
6349
6350 static const int kMaxInitialListCapacity = 16;
6351
danno@chromium.org40cb8782011-05-25 07:58:50 +00006352 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006353
6354 // Find (up to limit) indices of separator and end-of-string in subject
6355 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6356 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006357 if (!pattern->IsFlat()) FlattenString(pattern);
6358
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006359 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006360
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006361 if (static_cast<uint32_t>(indices.length()) < limit) {
6362 indices.Add(subject_length);
6363 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006364
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006365 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006366
6367 // Create JSArray of substrings separated by separator.
6368 int part_count = indices.length();
6369
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006370 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006371 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006372 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006373 result->set_length(Smi::FromInt(part_count));
6374
6375 ASSERT(result->HasFastElements());
6376
6377 if (part_count == 1 && indices.at(0) == subject_length) {
6378 FixedArray::cast(result->elements())->set(0, *subject);
6379 return *result;
6380 }
6381
6382 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6383 int part_start = 0;
6384 for (int i = 0; i < part_count; i++) {
6385 HandleScope local_loop_handle;
6386 int part_end = indices.at(i);
6387 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006388 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006389 elements->set(i, *substring);
6390 part_start = part_end + pattern_length;
6391 }
6392
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006393 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006394 if (result->HasFastElements()) {
6395 StringSplitCache::Enter(isolate->heap(),
6396 isolate->heap()->string_split_cache(),
6397 *subject,
6398 *pattern,
6399 *elements);
6400 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006401 }
6402
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006403 return *result;
6404}
6405
6406
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006407// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006408// one-char strings in the cache. Gives up on the first char that is
6409// not in the cache and fills the remainder with smi zeros. Returns
6410// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006411static int CopyCachedAsciiCharsToArray(Heap* heap,
6412 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006413 FixedArray* elements,
6414 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006415 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006416 FixedArray* ascii_cache = heap->single_character_string_cache();
6417 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006418 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006419 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006420 for (i = 0; i < length; ++i) {
6421 Object* value = ascii_cache->get(chars[i]);
6422 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006423 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006424 }
6425 if (i < length) {
6426 ASSERT(Smi::FromInt(0) == 0);
6427 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6428 }
6429#ifdef DEBUG
6430 for (int j = 0; j < length; ++j) {
6431 Object* element = elements->get(j);
6432 ASSERT(element == Smi::FromInt(0) ||
6433 (element->IsString() && String::cast(element)->LooksValid()));
6434 }
6435#endif
6436 return i;
6437}
6438
6439
6440// Converts a String to JSArray.
6441// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006442RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006443 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006444 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006445 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006446 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006447
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006448 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006449 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006450
6451 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006452 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006453 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006454 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006455 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006456 { MaybeObject* maybe_obj =
6457 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006458 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6459 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006460 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006461 String::FlatContent content = s->GetFlatContent();
6462 if (content.IsAscii()) {
6463 Vector<const char> chars = content.ToAsciiVector();
6464 // Note, this will initialize all elements (not only the prefix)
6465 // to prevent GC from seeing partially initialized array.
6466 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6467 chars.start(),
6468 *elements,
6469 length);
6470 } else {
6471 MemsetPointer(elements->data_start(),
6472 isolate->heap()->undefined_value(),
6473 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006474 }
6475 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006476 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006477 }
6478 for (int i = position; i < length; ++i) {
6479 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6480 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006481 }
6482
6483#ifdef DEBUG
6484 for (int i = 0; i < length; ++i) {
6485 ASSERT(String::cast(elements->get(i))->length() == 1);
6486 }
6487#endif
6488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006489 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006490}
6491
6492
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006493RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006494 NoHandleAllocation ha;
6495 ASSERT(args.length() == 1);
6496 CONVERT_CHECKED(String, value, args[0]);
6497 return value->ToObject();
6498}
6499
6500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006502 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006503 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006504 return char_length == 0;
6505}
6506
6507
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006508RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006509 NoHandleAllocation ha;
6510 ASSERT(args.length() == 1);
6511
6512 Object* number = args[0];
6513 RUNTIME_ASSERT(number->IsNumber());
6514
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006515 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006516}
6517
6518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006519RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006520 NoHandleAllocation ha;
6521 ASSERT(args.length() == 1);
6522
6523 Object* number = args[0];
6524 RUNTIME_ASSERT(number->IsNumber());
6525
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006526 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006527}
6528
6529
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006530RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006531 NoHandleAllocation ha;
6532 ASSERT(args.length() == 1);
6533
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006534 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006535
6536 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6537 if (number > 0 && number <= Smi::kMaxValue) {
6538 return Smi::FromInt(static_cast<int>(number));
6539 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006540 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006541}
6542
6543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006544RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006545 NoHandleAllocation ha;
6546 ASSERT(args.length() == 1);
6547
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006548 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006549
6550 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6551 if (number > 0 && number <= Smi::kMaxValue) {
6552 return Smi::FromInt(static_cast<int>(number));
6553 }
6554
6555 double double_value = DoubleToInteger(number);
6556 // Map both -0 and +0 to +0.
6557 if (double_value == 0) double_value = 0;
6558
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006559 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006560}
6561
6562
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006563RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564 NoHandleAllocation ha;
6565 ASSERT(args.length() == 1);
6566
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006567 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006568 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569}
6570
6571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006572RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006573 NoHandleAllocation ha;
6574 ASSERT(args.length() == 1);
6575
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006576 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006577
6578 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6579 if (number > 0 && number <= Smi::kMaxValue) {
6580 return Smi::FromInt(static_cast<int>(number));
6581 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006582 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583}
6584
6585
ager@chromium.org870a0b62008-11-04 11:43:05 +00006586// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6587// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006588RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006589 NoHandleAllocation ha;
6590 ASSERT(args.length() == 1);
6591
6592 Object* obj = args[0];
6593 if (obj->IsSmi()) {
6594 return obj;
6595 }
6596 if (obj->IsHeapNumber()) {
6597 double value = HeapNumber::cast(obj)->value();
6598 int int_value = FastD2I(value);
6599 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6600 return Smi::FromInt(int_value);
6601 }
6602 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006603 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006604}
6605
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006607RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006608 NoHandleAllocation ha;
6609 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006610 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006611}
6612
6613
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006614RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006615 NoHandleAllocation ha;
6616 ASSERT(args.length() == 2);
6617
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006618 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6619 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006620 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006621}
6622
6623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006624RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625 NoHandleAllocation ha;
6626 ASSERT(args.length() == 2);
6627
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006628 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6629 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006630 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006631}
6632
6633
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006634RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006635 NoHandleAllocation ha;
6636 ASSERT(args.length() == 2);
6637
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006638 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6639 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006640 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006641}
6642
6643
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006644RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006645 NoHandleAllocation ha;
6646 ASSERT(args.length() == 1);
6647
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006648 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006649 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006650}
6651
6652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006653RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006654 NoHandleAllocation ha;
6655 ASSERT(args.length() == 0);
6656
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006657 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006658}
6659
6660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006661RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006662 NoHandleAllocation ha;
6663 ASSERT(args.length() == 2);
6664
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006665 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6666 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006667 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006668}
6669
6670
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006671RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006672 NoHandleAllocation ha;
6673 ASSERT(args.length() == 2);
6674
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006675 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6676 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677
ager@chromium.org3811b432009-10-28 14:53:37 +00006678 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006679 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006680 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006681}
6682
6683
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006684RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006685 NoHandleAllocation ha;
6686 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006687 CONVERT_CHECKED(String, str1, args[0]);
6688 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006689 isolate->counters()->string_add_runtime()->Increment();
6690 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006691}
6692
6693
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006694template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006695static inline void StringBuilderConcatHelper(String* special,
6696 sinkchar* sink,
6697 FixedArray* fixed_array,
6698 int array_length) {
6699 int position = 0;
6700 for (int i = 0; i < array_length; i++) {
6701 Object* element = fixed_array->get(i);
6702 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006703 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006704 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006705 int pos;
6706 int len;
6707 if (encoded_slice > 0) {
6708 // Position and length encoded in one smi.
6709 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6710 len = StringBuilderSubstringLength::decode(encoded_slice);
6711 } else {
6712 // Position and length encoded in two smis.
6713 Object* obj = fixed_array->get(++i);
6714 ASSERT(obj->IsSmi());
6715 pos = Smi::cast(obj)->value();
6716 len = -encoded_slice;
6717 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006718 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006719 sink + position,
6720 pos,
6721 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006722 position += len;
6723 } else {
6724 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006725 int element_length = string->length();
6726 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006727 position += element_length;
6728 }
6729 }
6730}
6731
6732
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006733RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006734 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006735 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006736 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006737 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006738 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006739 return Failure::OutOfMemoryException();
6740 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006741 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006742 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006743
6744 // This assumption is used by the slice encoding in one or two smis.
6745 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6746
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006747 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006748 if (maybe_result->IsFailure()) return maybe_result;
6749
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006750 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006751 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753 }
6754 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006755 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006756 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006757 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006758
6759 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006760 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006761 } else if (array_length == 1) {
6762 Object* first = fixed_array->get(0);
6763 if (first->IsString()) return first;
6764 }
6765
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006766 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006767 int position = 0;
6768 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006769 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006770 Object* elt = fixed_array->get(i);
6771 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006772 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006773 int smi_value = Smi::cast(elt)->value();
6774 int pos;
6775 int len;
6776 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006777 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006778 pos = StringBuilderSubstringPosition::decode(smi_value);
6779 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006780 } else {
6781 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006782 len = -smi_value;
6783 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006784 i++;
6785 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006786 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006787 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006788 Object* next_smi = fixed_array->get(i);
6789 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006790 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006791 }
6792 pos = Smi::cast(next_smi)->value();
6793 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006794 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006795 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006797 ASSERT(pos >= 0);
6798 ASSERT(len >= 0);
6799 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006800 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006801 }
6802 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006803 } else if (elt->IsString()) {
6804 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006805 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006806 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006807 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006809 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006810 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006811 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006812 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006813 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006814 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006815 return Failure::OutOfMemoryException();
6816 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006817 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006818 }
6819
6820 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006821 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006822
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006823 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006824 { MaybeObject* maybe_object =
6825 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006826 if (!maybe_object->ToObject(&object)) return maybe_object;
6827 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006828 SeqAsciiString* answer = SeqAsciiString::cast(object);
6829 StringBuilderConcatHelper(special,
6830 answer->GetChars(),
6831 fixed_array,
6832 array_length);
6833 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006834 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006835 { MaybeObject* maybe_object =
6836 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006837 if (!maybe_object->ToObject(&object)) return maybe_object;
6838 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006839 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6840 StringBuilderConcatHelper(special,
6841 answer->GetChars(),
6842 fixed_array,
6843 array_length);
6844 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006845 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006846}
6847
6848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006849RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006850 NoHandleAllocation ha;
6851 ASSERT(args.length() == 3);
6852 CONVERT_CHECKED(JSArray, array, args[0]);
6853 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006854 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006855 return Failure::OutOfMemoryException();
6856 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006857 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006858 CONVERT_CHECKED(String, separator, args[2]);
6859
6860 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006861 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006862 }
6863 FixedArray* fixed_array = FixedArray::cast(array->elements());
6864 if (fixed_array->length() < array_length) {
6865 array_length = fixed_array->length();
6866 }
6867
6868 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006869 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006870 } else if (array_length == 1) {
6871 Object* first = fixed_array->get(0);
6872 if (first->IsString()) return first;
6873 }
6874
6875 int separator_length = separator->length();
6876 int max_nof_separators =
6877 (String::kMaxLength + separator_length - 1) / separator_length;
6878 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006879 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006880 return Failure::OutOfMemoryException();
6881 }
6882 int length = (array_length - 1) * separator_length;
6883 for (int i = 0; i < array_length; i++) {
6884 Object* element_obj = fixed_array->get(i);
6885 if (!element_obj->IsString()) {
6886 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006887 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006888 }
6889 String* element = String::cast(element_obj);
6890 int increment = element->length();
6891 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006892 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006893 return Failure::OutOfMemoryException();
6894 }
6895 length += increment;
6896 }
6897
6898 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006899 { MaybeObject* maybe_object =
6900 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006901 if (!maybe_object->ToObject(&object)) return maybe_object;
6902 }
6903 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6904
6905 uc16* sink = answer->GetChars();
6906#ifdef DEBUG
6907 uc16* end = sink + length;
6908#endif
6909
6910 String* first = String::cast(fixed_array->get(0));
6911 int first_length = first->length();
6912 String::WriteToFlat(first, sink, 0, first_length);
6913 sink += first_length;
6914
6915 for (int i = 1; i < array_length; i++) {
6916 ASSERT(sink + separator_length <= end);
6917 String::WriteToFlat(separator, sink, 0, separator_length);
6918 sink += separator_length;
6919
6920 String* element = String::cast(fixed_array->get(i));
6921 int element_length = element->length();
6922 ASSERT(sink + element_length <= end);
6923 String::WriteToFlat(element, sink, 0, element_length);
6924 sink += element_length;
6925 }
6926 ASSERT(sink == end);
6927
6928 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6929 return answer;
6930}
6931
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006932template <typename Char>
6933static void JoinSparseArrayWithSeparator(FixedArray* elements,
6934 int elements_length,
6935 uint32_t array_length,
6936 String* separator,
6937 Vector<Char> buffer) {
6938 int previous_separator_position = 0;
6939 int separator_length = separator->length();
6940 int cursor = 0;
6941 for (int i = 0; i < elements_length; i += 2) {
6942 int position = NumberToInt32(elements->get(i));
6943 String* string = String::cast(elements->get(i + 1));
6944 int string_length = string->length();
6945 if (string->length() > 0) {
6946 while (previous_separator_position < position) {
6947 String::WriteToFlat<Char>(separator, &buffer[cursor],
6948 0, separator_length);
6949 cursor += separator_length;
6950 previous_separator_position++;
6951 }
6952 String::WriteToFlat<Char>(string, &buffer[cursor],
6953 0, string_length);
6954 cursor += string->length();
6955 }
6956 }
6957 if (separator_length > 0) {
6958 // Array length must be representable as a signed 32-bit number,
6959 // otherwise the total string length would have been too large.
6960 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6961 int last_array_index = static_cast<int>(array_length - 1);
6962 while (previous_separator_position < last_array_index) {
6963 String::WriteToFlat<Char>(separator, &buffer[cursor],
6964 0, separator_length);
6965 cursor += separator_length;
6966 previous_separator_position++;
6967 }
6968 }
6969 ASSERT(cursor <= buffer.length());
6970}
6971
6972
6973RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6974 NoHandleAllocation ha;
6975 ASSERT(args.length() == 3);
6976 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006977 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6978 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006979 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6980 CONVERT_CHECKED(String, separator, args[2]);
6981 // elements_array is fast-mode JSarray of alternating positions
6982 // (increasing order) and strings.
6983 // array_length is length of original array (used to add separators);
6984 // separator is string to put between elements. Assumed to be non-empty.
6985
6986 // Find total length of join result.
6987 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006988 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006989 int max_string_length;
6990 if (is_ascii) {
6991 max_string_length = SeqAsciiString::kMaxLength;
6992 } else {
6993 max_string_length = SeqTwoByteString::kMaxLength;
6994 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006995 bool overflow = false;
6996 CONVERT_NUMBER_CHECKED(int, elements_length,
6997 Int32, elements_array->length());
6998 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6999 FixedArray* elements = FixedArray::cast(elements_array->elements());
7000 for (int i = 0; i < elements_length; i += 2) {
7001 RUNTIME_ASSERT(elements->get(i)->IsNumber());
7002 CONVERT_CHECKED(String, string, elements->get(i + 1));
7003 int length = string->length();
7004 if (is_ascii && !string->IsAsciiRepresentation()) {
7005 is_ascii = false;
7006 max_string_length = SeqTwoByteString::kMaxLength;
7007 }
7008 if (length > max_string_length ||
7009 max_string_length - length < string_length) {
7010 overflow = true;
7011 break;
7012 }
7013 string_length += length;
7014 }
7015 int separator_length = separator->length();
7016 if (!overflow && separator_length > 0) {
7017 if (array_length <= 0x7fffffffu) {
7018 int separator_count = static_cast<int>(array_length) - 1;
7019 int remaining_length = max_string_length - string_length;
7020 if ((remaining_length / separator_length) >= separator_count) {
7021 string_length += separator_length * (array_length - 1);
7022 } else {
7023 // Not room for the separators within the maximal string length.
7024 overflow = true;
7025 }
7026 } else {
7027 // Nonempty separator and at least 2^31-1 separators necessary
7028 // means that the string is too large to create.
7029 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7030 overflow = true;
7031 }
7032 }
7033 if (overflow) {
7034 // Throw OutOfMemory exception for creating too large a string.
7035 V8::FatalProcessOutOfMemory("Array join result too large.");
7036 }
7037
7038 if (is_ascii) {
7039 MaybeObject* result_allocation =
7040 isolate->heap()->AllocateRawAsciiString(string_length);
7041 if (result_allocation->IsFailure()) return result_allocation;
7042 SeqAsciiString* result_string =
7043 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7044 JoinSparseArrayWithSeparator<char>(elements,
7045 elements_length,
7046 array_length,
7047 separator,
7048 Vector<char>(result_string->GetChars(),
7049 string_length));
7050 return result_string;
7051 } else {
7052 MaybeObject* result_allocation =
7053 isolate->heap()->AllocateRawTwoByteString(string_length);
7054 if (result_allocation->IsFailure()) return result_allocation;
7055 SeqTwoByteString* result_string =
7056 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7057 JoinSparseArrayWithSeparator<uc16>(elements,
7058 elements_length,
7059 array_length,
7060 separator,
7061 Vector<uc16>(result_string->GetChars(),
7062 string_length));
7063 return result_string;
7064 }
7065}
7066
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007068RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007069 NoHandleAllocation ha;
7070 ASSERT(args.length() == 2);
7071
7072 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7073 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007074 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007075}
7076
7077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007078RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007079 NoHandleAllocation ha;
7080 ASSERT(args.length() == 2);
7081
7082 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7083 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007084 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007085}
7086
7087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007088RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007089 NoHandleAllocation ha;
7090 ASSERT(args.length() == 2);
7091
7092 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7093 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007094 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007095}
7096
7097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007098RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007099 NoHandleAllocation ha;
7100 ASSERT(args.length() == 1);
7101
7102 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007103 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007104}
7105
7106
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007107RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007108 NoHandleAllocation ha;
7109 ASSERT(args.length() == 2);
7110
7111 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7112 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007113 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007114}
7115
7116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007117RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007118 NoHandleAllocation ha;
7119 ASSERT(args.length() == 2);
7120
7121 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7122 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007123 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007124}
7125
7126
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007127RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007128 NoHandleAllocation ha;
7129 ASSERT(args.length() == 2);
7130
7131 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7132 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007133 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007134}
7135
7136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007137RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007138 NoHandleAllocation ha;
7139 ASSERT(args.length() == 2);
7140
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007141 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7142 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007143 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7144 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7145 if (x == y) return Smi::FromInt(EQUAL);
7146 Object* result;
7147 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7148 result = Smi::FromInt(EQUAL);
7149 } else {
7150 result = Smi::FromInt(NOT_EQUAL);
7151 }
7152 return result;
7153}
7154
7155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007156RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007157 NoHandleAllocation ha;
7158 ASSERT(args.length() == 2);
7159
7160 CONVERT_CHECKED(String, x, args[0]);
7161 CONVERT_CHECKED(String, y, args[1]);
7162
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007163 bool not_equal = !x->Equals(y);
7164 // This is slightly convoluted because the value that signifies
7165 // equality is 0 and inequality is 1 so we have to negate the result
7166 // from String::Equals.
7167 ASSERT(not_equal == 0 || not_equal == 1);
7168 STATIC_CHECK(EQUAL == 0);
7169 STATIC_CHECK(NOT_EQUAL == 1);
7170 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007171}
7172
7173
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007174RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007175 NoHandleAllocation ha;
7176 ASSERT(args.length() == 3);
7177
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007178 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7179 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007180 if (isnan(x) || isnan(y)) return args[2];
7181 if (x == y) return Smi::FromInt(EQUAL);
7182 if (isless(x, y)) return Smi::FromInt(LESS);
7183 return Smi::FromInt(GREATER);
7184}
7185
7186
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007187// Compare two Smis as if they were converted to strings and then
7188// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007189RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007190 NoHandleAllocation ha;
7191 ASSERT(args.length() == 2);
7192
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007193 // Extract the integer values from the Smis.
7194 CONVERT_CHECKED(Smi, x, args[0]);
7195 CONVERT_CHECKED(Smi, y, args[1]);
7196 int x_value = x->value();
7197 int y_value = y->value();
7198
7199 // If the integers are equal so are the string representations.
7200 if (x_value == y_value) return Smi::FromInt(EQUAL);
7201
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007202 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007203 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007204 if (x_value == 0 || y_value == 0)
7205 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007206
ager@chromium.org32912102009-01-16 10:38:43 +00007207 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007208 // smallest because the char code of '-' is less than the char code
7209 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007210
7211 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7212 // architectures using 32-bit Smis.
7213 uint32_t x_scaled = x_value;
7214 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007215 if (x_value < 0 || y_value < 0) {
7216 if (y_value >= 0) return Smi::FromInt(LESS);
7217 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007218 x_scaled = -x_value;
7219 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007220 }
7221
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007222 static const uint32_t kPowersOf10[] = {
7223 1, 10, 100, 1000, 10*1000, 100*1000,
7224 1000*1000, 10*1000*1000, 100*1000*1000,
7225 1000*1000*1000
7226 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007227
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007228 // If the integers have the same number of decimal digits they can be
7229 // compared directly as the numeric order is the same as the
7230 // lexicographic order. If one integer has fewer digits, it is scaled
7231 // by some power of 10 to have the same number of digits as the longer
7232 // integer. If the scaled integers are equal it means the shorter
7233 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007234
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007235 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7236 int x_log2 = IntegerLog2(x_scaled);
7237 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7238 x_log10 -= x_scaled < kPowersOf10[x_log10];
7239
7240 int y_log2 = IntegerLog2(y_scaled);
7241 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7242 y_log10 -= y_scaled < kPowersOf10[y_log10];
7243
7244 int tie = EQUAL;
7245
7246 if (x_log10 < y_log10) {
7247 // X has fewer digits. We would like to simply scale up X but that
7248 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7249 // be scaled up to 9_000_000_000. So we scale up by the next
7250 // smallest power and scale down Y to drop one digit. It is OK to
7251 // drop one digit from the longer integer since the final digit is
7252 // past the length of the shorter integer.
7253 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7254 y_scaled /= 10;
7255 tie = LESS;
7256 } else if (y_log10 < x_log10) {
7257 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7258 x_scaled /= 10;
7259 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007260 }
7261
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007262 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7263 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7264 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007265}
7266
7267
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007268static Object* StringInputBufferCompare(RuntimeState* state,
7269 String* x,
7270 String* y) {
7271 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7272 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007273 bufx.Reset(x);
7274 bufy.Reset(y);
7275 while (bufx.has_more() && bufy.has_more()) {
7276 int d = bufx.GetNext() - bufy.GetNext();
7277 if (d < 0) return Smi::FromInt(LESS);
7278 else if (d > 0) return Smi::FromInt(GREATER);
7279 }
7280
7281 // x is (non-trivial) prefix of y:
7282 if (bufy.has_more()) return Smi::FromInt(LESS);
7283 // y is prefix of x:
7284 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7285}
7286
7287
7288static Object* FlatStringCompare(String* x, String* y) {
7289 ASSERT(x->IsFlat());
7290 ASSERT(y->IsFlat());
7291 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7292 int prefix_length = x->length();
7293 if (y->length() < prefix_length) {
7294 prefix_length = y->length();
7295 equal_prefix_result = Smi::FromInt(GREATER);
7296 } else if (y->length() > prefix_length) {
7297 equal_prefix_result = Smi::FromInt(LESS);
7298 }
7299 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007300 String::FlatContent x_content = x->GetFlatContent();
7301 String::FlatContent y_content = y->GetFlatContent();
7302 if (x_content.IsAscii()) {
7303 Vector<const char> x_chars = x_content.ToAsciiVector();
7304 if (y_content.IsAscii()) {
7305 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007306 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007307 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007308 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007309 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7310 }
7311 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007312 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7313 if (y_content.IsAscii()) {
7314 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007315 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7316 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007317 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007318 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7319 }
7320 }
7321 Object* result;
7322 if (r == 0) {
7323 result = equal_prefix_result;
7324 } else {
7325 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7326 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007327 ASSERT(result ==
7328 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007329 return result;
7330}
7331
7332
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007333RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007334 NoHandleAllocation ha;
7335 ASSERT(args.length() == 2);
7336
7337 CONVERT_CHECKED(String, x, args[0]);
7338 CONVERT_CHECKED(String, y, args[1]);
7339
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007341
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007342 // A few fast case tests before we flatten.
7343 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007344 if (y->length() == 0) {
7345 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007347 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007348 return Smi::FromInt(LESS);
7349 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007350
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007351 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007352 if (d < 0) return Smi::FromInt(LESS);
7353 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354
lrn@chromium.org303ada72010-10-27 09:33:13 +00007355 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007356 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007357 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7358 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007359 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007360 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7361 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007362
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007363 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007364 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007365}
7366
7367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007368RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007369 NoHandleAllocation ha;
7370 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007371 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007372
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007373 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007374 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007375}
7376
7377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007378RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007379 NoHandleAllocation ha;
7380 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007381 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007382
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007383 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007384 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385}
7386
7387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007388RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007389 NoHandleAllocation ha;
7390 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007391 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007392
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007393 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395}
7396
7397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007398static const double kPiDividedBy4 = 0.78539816339744830962;
7399
7400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007401RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007402 NoHandleAllocation ha;
7403 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007404 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007405
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007406 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7407 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408 double result;
7409 if (isinf(x) && isinf(y)) {
7410 // Make sure that the result in case of two infinite arguments
7411 // is a multiple of Pi / 4. The sign of the result is determined
7412 // by the first argument (x) and the sign of the second argument
7413 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007414 int multiplier = (x < 0) ? -1 : 1;
7415 if (y < 0) multiplier *= 3;
7416 result = multiplier * kPiDividedBy4;
7417 } else {
7418 result = atan2(x, y);
7419 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007420 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007421}
7422
7423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007424RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007425 NoHandleAllocation ha;
7426 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007427 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007428
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007429 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007430 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007431}
7432
7433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007434RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007435 NoHandleAllocation ha;
7436 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007437 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007438
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007439 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007440 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007441}
7442
7443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007444RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007445 NoHandleAllocation ha;
7446 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007447 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007448
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007449 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007450 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451}
7452
7453
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007454RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007455 NoHandleAllocation ha;
7456 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007457 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007458
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007459 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007460 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007461}
7462
7463
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007464RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007465 NoHandleAllocation ha;
7466 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007467 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007468
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007469 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007470 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007471}
7472
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007473// Slow version of Math.pow. We check for fast paths for special cases.
7474// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007475RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007476 NoHandleAllocation ha;
7477 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007478 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007479
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007480 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007481
7482 // If the second argument is a smi, it is much faster to call the
7483 // custom powi() function than the generic pow().
7484 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007485 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007486 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007487 }
7488
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007489 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007490 int y_int = static_cast<int>(y);
7491 double result;
7492 if (y == y_int) {
7493 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7494 } else if (y == 0.5) {
7495 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7496 } else if (y == -0.5) {
7497 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7498 } else {
7499 result = power_double_double(x, y);
7500 }
7501 if (isnan(result)) return isolate->heap()->nan_value();
7502 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007503}
7504
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007505// Fast version of Math.pow if we know that y is not an integer and y is not
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007506// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007507RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007508 NoHandleAllocation ha;
7509 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007510 isolate->counters()->math_pow()->Increment();
7511
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007512 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7513 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007514 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007515 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007516 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007517 double result = power_double_double(x, y);
7518 if (isnan(result)) return isolate->heap()->nan_value();
7519 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007520 }
7521}
7522
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007524RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007525 NoHandleAllocation ha;
7526 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007527 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007528
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007529 if (!args[0]->IsHeapNumber()) {
7530 // Must be smi. Return the argument unchanged for all the other types
7531 // to make fuzz-natives test happy.
7532 return args[0];
7533 }
7534
7535 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7536
7537 double value = number->value();
7538 int exponent = number->get_exponent();
7539 int sign = number->get_sign();
7540
danno@chromium.org160a7b02011-04-18 15:51:38 +00007541 if (exponent < -1) {
7542 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7543 if (sign) return isolate->heap()->minus_zero_value();
7544 return Smi::FromInt(0);
7545 }
7546
7547 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7548 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007549 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007550 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007551 return Smi::FromInt(static_cast<int>(value + 0.5));
7552 }
7553
7554 // If the magnitude is big enough, there's no place for fraction part. If we
7555 // try to add 0.5 to this number, 1.0 will be added instead.
7556 if (exponent >= 52) {
7557 return number;
7558 }
7559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007560 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007561
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007562 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007563 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007564}
7565
7566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007567RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007568 NoHandleAllocation ha;
7569 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007570 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007571
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007572 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007573 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007574}
7575
7576
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007577RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007578 NoHandleAllocation ha;
7579 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007580 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007581
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007582 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007583 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007584}
7585
7586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007587RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007588 NoHandleAllocation ha;
7589 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007590 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007591
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007592 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007593 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007594}
7595
7596
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007597static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007598 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7599 181, 212, 243, 273, 304, 334};
7600 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7601 182, 213, 244, 274, 305, 335};
7602
7603 year += month / 12;
7604 month %= 12;
7605 if (month < 0) {
7606 year--;
7607 month += 12;
7608 }
7609
7610 ASSERT(month >= 0);
7611 ASSERT(month < 12);
7612
7613 // year_delta is an arbitrary number such that:
7614 // a) year_delta = -1 (mod 400)
7615 // b) year + year_delta > 0 for years in the range defined by
7616 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7617 // Jan 1 1970. This is required so that we don't run into integer
7618 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007619 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007620 // operations.
7621 static const int year_delta = 399999;
7622 static const int base_day = 365 * (1970 + year_delta) +
7623 (1970 + year_delta) / 4 -
7624 (1970 + year_delta) / 100 +
7625 (1970 + year_delta) / 400;
7626
7627 int year1 = year + year_delta;
7628 int day_from_year = 365 * year1 +
7629 year1 / 4 -
7630 year1 / 100 +
7631 year1 / 400 -
7632 base_day;
7633
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007634 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7635 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007636 }
7637
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007638 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007639}
7640
7641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007642RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007643 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007644 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007645
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007646 CONVERT_SMI_ARG_CHECKED(year, 0);
7647 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007648
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007649 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007650}
7651
7652
7653static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7654static const int kDaysIn4Years = 4 * 365 + 1;
7655static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7656static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7657static const int kDays1970to2000 = 30 * 365 + 7;
7658static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7659 kDays1970to2000;
7660static const int kYearsOffset = 400000;
7661
7662static const char kDayInYear[] = {
7663 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7664 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7665 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7666 22, 23, 24, 25, 26, 27, 28,
7667 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7668 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7669 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7670 22, 23, 24, 25, 26, 27, 28, 29, 30,
7671 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7672 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7673 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7674 22, 23, 24, 25, 26, 27, 28, 29, 30,
7675 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7676 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7677 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7678 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7679 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7680 22, 23, 24, 25, 26, 27, 28, 29, 30,
7681 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7682 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7683 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7684 22, 23, 24, 25, 26, 27, 28, 29, 30,
7685 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7686 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7687
7688 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7689 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7690 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7691 22, 23, 24, 25, 26, 27, 28,
7692 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7693 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7694 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7695 22, 23, 24, 25, 26, 27, 28, 29, 30,
7696 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7697 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7698 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7699 22, 23, 24, 25, 26, 27, 28, 29, 30,
7700 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7701 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7702 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7703 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7704 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7705 22, 23, 24, 25, 26, 27, 28, 29, 30,
7706 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7707 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7708 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7709 22, 23, 24, 25, 26, 27, 28, 29, 30,
7710 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7711 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7712
7713 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7714 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7715 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7716 22, 23, 24, 25, 26, 27, 28, 29,
7717 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7718 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7719 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7720 22, 23, 24, 25, 26, 27, 28, 29, 30,
7721 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7722 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7723 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7724 22, 23, 24, 25, 26, 27, 28, 29, 30,
7725 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7726 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7727 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7728 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7729 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7730 22, 23, 24, 25, 26, 27, 28, 29, 30,
7731 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7732 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7733 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7734 22, 23, 24, 25, 26, 27, 28, 29, 30,
7735 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7736 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7737
7738 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7739 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7740 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7741 22, 23, 24, 25, 26, 27, 28,
7742 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7743 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7744 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7745 22, 23, 24, 25, 26, 27, 28, 29, 30,
7746 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7747 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7748 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7749 22, 23, 24, 25, 26, 27, 28, 29, 30,
7750 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7751 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7752 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7753 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7754 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7755 22, 23, 24, 25, 26, 27, 28, 29, 30,
7756 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7757 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7758 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7759 22, 23, 24, 25, 26, 27, 28, 29, 30,
7760 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7761 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7762
7763static const char kMonthInYear[] = {
7764 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7765 0, 0, 0, 0, 0, 0,
7766 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7767 1, 1, 1,
7768 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7769 2, 2, 2, 2, 2, 2,
7770 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7771 3, 3, 3, 3, 3,
7772 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7773 4, 4, 4, 4, 4, 4,
7774 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7775 5, 5, 5, 5, 5,
7776 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7777 6, 6, 6, 6, 6, 6,
7778 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7779 7, 7, 7, 7, 7, 7,
7780 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7781 8, 8, 8, 8, 8,
7782 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7783 9, 9, 9, 9, 9, 9,
7784 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7785 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7786 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7787 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7788
7789 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7790 0, 0, 0, 0, 0, 0,
7791 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7792 1, 1, 1,
7793 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7794 2, 2, 2, 2, 2, 2,
7795 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7796 3, 3, 3, 3, 3,
7797 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7798 4, 4, 4, 4, 4, 4,
7799 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7800 5, 5, 5, 5, 5,
7801 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7802 6, 6, 6, 6, 6, 6,
7803 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7804 7, 7, 7, 7, 7, 7,
7805 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7806 8, 8, 8, 8, 8,
7807 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7808 9, 9, 9, 9, 9, 9,
7809 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7810 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7811 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7812 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7813
7814 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7815 0, 0, 0, 0, 0, 0,
7816 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7817 1, 1, 1, 1,
7818 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7819 2, 2, 2, 2, 2, 2,
7820 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7821 3, 3, 3, 3, 3,
7822 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7823 4, 4, 4, 4, 4, 4,
7824 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7825 5, 5, 5, 5, 5,
7826 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7827 6, 6, 6, 6, 6, 6,
7828 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7829 7, 7, 7, 7, 7, 7,
7830 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7831 8, 8, 8, 8, 8,
7832 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7833 9, 9, 9, 9, 9, 9,
7834 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7835 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7836 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7837 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7838
7839 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7840 0, 0, 0, 0, 0, 0,
7841 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7842 1, 1, 1,
7843 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7844 2, 2, 2, 2, 2, 2,
7845 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7846 3, 3, 3, 3, 3,
7847 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7848 4, 4, 4, 4, 4, 4,
7849 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7850 5, 5, 5, 5, 5,
7851 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7852 6, 6, 6, 6, 6, 6,
7853 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7854 7, 7, 7, 7, 7, 7,
7855 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7856 8, 8, 8, 8, 8,
7857 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7858 9, 9, 9, 9, 9, 9,
7859 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7860 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7861 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7862 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7863
7864
7865// This function works for dates from 1970 to 2099.
7866static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007867 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007868#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007869 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007870#endif
7871
7872 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7873 date %= kDaysIn4Years;
7874
7875 month = kMonthInYear[date];
7876 day = kDayInYear[date];
7877
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007878 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007879}
7880
7881
7882static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007883 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007884#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007885 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007886#endif
7887
7888 date += kDaysOffset;
7889 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7890 date %= kDaysIn400Years;
7891
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007892 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007893
7894 date--;
7895 int yd1 = date / kDaysIn100Years;
7896 date %= kDaysIn100Years;
7897 year += 100 * yd1;
7898
7899 date++;
7900 int yd2 = date / kDaysIn4Years;
7901 date %= kDaysIn4Years;
7902 year += 4 * yd2;
7903
7904 date--;
7905 int yd3 = date / 365;
7906 date %= 365;
7907 year += yd3;
7908
7909 bool is_leap = (!yd1 || yd2) && !yd3;
7910
7911 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007912 ASSERT(is_leap || (date >= 0));
7913 ASSERT((date < 365) || (is_leap && (date < 366)));
7914 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007915 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7916 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007917
7918 if (is_leap) {
7919 day = kDayInYear[2*365 + 1 + date];
7920 month = kMonthInYear[2*365 + 1 + date];
7921 } else {
7922 day = kDayInYear[date];
7923 month = kMonthInYear[date];
7924 }
7925
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007926 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007927}
7928
7929
7930static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007931 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007932 if (date >= 0 && date < 32 * kDaysIn4Years) {
7933 DateYMDFromTimeAfter1970(date, year, month, day);
7934 } else {
7935 DateYMDFromTimeSlow(date, year, month, day);
7936 }
7937}
7938
7939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007940RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007941 NoHandleAllocation ha;
7942 ASSERT(args.length() == 2);
7943
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007944 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007945 CONVERT_CHECKED(JSArray, res_array, args[1]);
7946
7947 int year, month, day;
7948 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7949
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007950 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7951 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007952 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007953
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007954 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7955 if (maybe->IsFailure()) return maybe;
7956 FixedArray* elms = FixedArray::cast(res_array->elements());
7957 elms->set(0, Smi::FromInt(year));
7958 elms->set(1, Smi::FromInt(month));
7959 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007960
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007961 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007962}
7963
7964
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007965RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007966 HandleScope scope(isolate);
7967 ASSERT(args.length() == 3);
7968
7969 Handle<JSFunction> callee = args.at<JSFunction>(0);
7970 Object** parameters = reinterpret_cast<Object**>(args[1]);
7971 const int argument_count = Smi::cast(args[2])->value();
7972
7973 Handle<JSObject> result =
7974 isolate->factory()->NewArgumentsObject(callee, argument_count);
7975 // Allocate the elements if needed.
7976 int parameter_count = callee->shared()->formal_parameter_count();
7977 if (argument_count > 0) {
7978 if (parameter_count > 0) {
7979 int mapped_count = Min(argument_count, parameter_count);
7980 Handle<FixedArray> parameter_map =
7981 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7982 parameter_map->set_map(
7983 isolate->heap()->non_strict_arguments_elements_map());
7984
7985 Handle<Map> old_map(result->map());
7986 Handle<Map> new_map =
7987 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007988 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007989
7990 result->set_map(*new_map);
7991 result->set_elements(*parameter_map);
7992
7993 // Store the context and the arguments array at the beginning of the
7994 // parameter map.
7995 Handle<Context> context(isolate->context());
7996 Handle<FixedArray> arguments =
7997 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7998 parameter_map->set(0, *context);
7999 parameter_map->set(1, *arguments);
8000
8001 // Loop over the actual parameters backwards.
8002 int index = argument_count - 1;
8003 while (index >= mapped_count) {
8004 // These go directly in the arguments array and have no
8005 // corresponding slot in the parameter map.
8006 arguments->set(index, *(parameters - index - 1));
8007 --index;
8008 }
8009
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008010 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00008011 while (index >= 0) {
8012 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008013 Handle<String> name(scope_info->ParameterName(index));
8014 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00008015 bool duplicate = false;
8016 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008017 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008018 duplicate = true;
8019 break;
8020 }
8021 }
8022
8023 if (duplicate) {
8024 // This goes directly in the arguments array with a hole in the
8025 // parameter map.
8026 arguments->set(index, *(parameters - index - 1));
8027 parameter_map->set_the_hole(index + 2);
8028 } else {
8029 // The context index goes in the parameter map with a hole in the
8030 // arguments array.
8031 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008032 for (int j = 0; j < context_local_count; ++j) {
8033 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008034 context_index = j;
8035 break;
8036 }
8037 }
8038 ASSERT(context_index >= 0);
8039 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008040 parameter_map->set(index + 2, Smi::FromInt(
8041 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00008042 }
8043
8044 --index;
8045 }
8046 } else {
8047 // If there is no aliasing, the arguments object elements are not
8048 // special in any way.
8049 Handle<FixedArray> elements =
8050 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8051 result->set_elements(*elements);
8052 for (int i = 0; i < argument_count; ++i) {
8053 elements->set(i, *(parameters - i - 1));
8054 }
8055 }
8056 }
8057 return *result;
8058}
8059
8060
8061RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008062 NoHandleAllocation ha;
8063 ASSERT(args.length() == 3);
8064
8065 JSFunction* callee = JSFunction::cast(args[0]);
8066 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008067 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008068
lrn@chromium.org303ada72010-10-27 09:33:13 +00008069 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008070 { MaybeObject* maybe_result =
8071 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008072 if (!maybe_result->ToObject(&result)) return maybe_result;
8073 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008074 // Allocate the elements if needed.
8075 if (length > 0) {
8076 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008077 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008078 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008079 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8080 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008081
8082 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008083 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008084 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008085 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008086
8087 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008088 for (int i = 0; i < length; i++) {
8089 array->set(i, *--parameters, mode);
8090 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008091 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008092 }
8093 return result;
8094}
8095
8096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008097RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008098 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008099 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008100 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008101 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008102 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008103
whesse@chromium.org7b260152011-06-20 15:33:18 +00008104 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008105 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008106 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008107 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008108 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8109 context,
8110 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008111 return *result;
8112}
8113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008114
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008115// Find the arguments of the JavaScript function invocation that called
8116// into C++ code. Collect these in a newly allocated array of handles (possibly
8117// prefixed by a number of empty handles).
8118static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8119 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008120 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008121 // Find frame containing arguments passed to the caller.
8122 JavaScriptFrameIterator it;
8123 JavaScriptFrame* frame = it.frame();
8124 List<JSFunction*> functions(2);
8125 frame->GetFunctions(&functions);
8126 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008127 int inlined_jsframe_index = functions.length() - 1;
8128 JSFunction* inlined_function = functions[inlined_jsframe_index];
8129 Vector<SlotRef> args_slots =
8130 SlotRef::ComputeSlotMappingForArguments(
8131 frame,
8132 inlined_jsframe_index,
8133 inlined_function->shared()->formal_parameter_count());
8134
8135 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008136
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008137 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008138 SmartArrayPointer<Handle<Object> > param_data(
8139 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008140 for (int i = 0; i < args_count; i++) {
8141 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008142 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008143 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008144
8145 args_slots.Dispose();
8146
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008147 return param_data;
8148 } else {
8149 it.AdvanceToArgumentsFrame();
8150 frame = it.frame();
8151 int args_count = frame->ComputeParametersCount();
8152
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008153 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008154 SmartArrayPointer<Handle<Object> > param_data(
8155 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008156 for (int i = 0; i < args_count; i++) {
8157 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008158 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008159 }
8160 return param_data;
8161 }
8162}
8163
8164
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008165RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8166 HandleScope scope(isolate);
8167 ASSERT(args.length() == 4);
8168 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8169 RUNTIME_ASSERT(args[3]->IsNumber());
8170 Handle<Object> bindee = args.at<Object>(1);
8171
8172 // TODO(lrn): Create bound function in C++ code from premade shared info.
8173 bound_function->shared()->set_bound(true);
8174 // Get all arguments of calling function (Function.prototype.bind).
8175 int argc = 0;
8176 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8177 // Don't count the this-arg.
8178 if (argc > 0) {
8179 ASSERT(*arguments[0] == args[2]);
8180 argc--;
8181 } else {
8182 ASSERT(args[2]->IsUndefined());
8183 }
8184 // Initialize array of bindings (function, this, and any existing arguments
8185 // if the function was already bound).
8186 Handle<FixedArray> new_bindings;
8187 int i;
8188 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8189 Handle<FixedArray> old_bindings(
8190 JSFunction::cast(*bindee)->function_bindings());
8191 new_bindings =
8192 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8193 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8194 i = 0;
8195 for (int n = old_bindings->length(); i < n; i++) {
8196 new_bindings->set(i, old_bindings->get(i));
8197 }
8198 } else {
8199 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8200 new_bindings = isolate->factory()->NewFixedArray(array_size);
8201 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8202 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8203 i = 2;
8204 }
8205 // Copy arguments, skipping the first which is "this_arg".
8206 for (int j = 0; j < argc; j++, i++) {
8207 new_bindings->set(i, *arguments[j + 1]);
8208 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008209 new_bindings->set_map_no_write_barrier(
8210 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008211 bound_function->set_function_bindings(*new_bindings);
8212
8213 // Update length.
8214 Handle<String> length_symbol = isolate->factory()->length_symbol();
8215 Handle<Object> new_length(args.at<Object>(3));
8216 PropertyAttributes attr =
8217 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8218 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8219 return *bound_function;
8220}
8221
8222
8223RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8224 HandleScope handles(isolate);
8225 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008226 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008227 if (callable->IsJSFunction()) {
8228 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8229 if (function->shared()->bound()) {
8230 Handle<FixedArray> bindings(function->function_bindings());
8231 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8232 return *isolate->factory()->NewJSArrayWithElements(bindings);
8233 }
8234 }
8235 return isolate->heap()->undefined_value();
8236}
8237
8238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008239RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008240 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008241 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008242 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008243 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008244 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008245
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008246 // The argument is a bound function. Extract its bound arguments
8247 // and callable.
8248 Handle<FixedArray> bound_args =
8249 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8250 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8251 Handle<Object> bound_function(
8252 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8253 ASSERT(!bound_function->IsJSFunction() ||
8254 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008256 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008257 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008258 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008259 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008260 param_data[i] = Handle<Object>(bound_args->get(
8261 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008262 }
8263
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008264 if (!bound_function->IsJSFunction()) {
8265 bool exception_thrown;
8266 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8267 &exception_thrown);
8268 if (exception_thrown) return Failure::Exception();
8269 }
8270 ASSERT(bound_function->IsJSFunction());
8271
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008272 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008273 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008274 Execution::New(Handle<JSFunction>::cast(bound_function),
8275 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008276 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008277 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008278 }
8279 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008280 return *result;
8281}
8282
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008283
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008284static void TrySettingInlineConstructStub(Isolate* isolate,
8285 Handle<JSFunction> function) {
8286 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008287 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008288 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008289 }
8290 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008291 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008292 Handle<Code> code = compiler.CompileConstructStub(function);
8293 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008294 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008295}
8296
8297
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008298RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008299 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008300 ASSERT(args.length() == 1);
8301
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008302 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008303
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008304 // If the constructor isn't a proper function we throw a type error.
8305 if (!constructor->IsJSFunction()) {
8306 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8307 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008308 isolate->factory()->NewTypeError("not_constructor", arguments);
8309 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008310 }
8311
8312 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008313
8314 // If function should not have prototype, construction is not allowed. In this
8315 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008316 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008317 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8318 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008319 isolate->factory()->NewTypeError("not_constructor", arguments);
8320 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008321 }
8322
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008323#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008324 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008325 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008326 if (debug->StepInActive()) {
8327 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008328 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008329#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008330
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008331 if (function->has_initial_map()) {
8332 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008333 // The 'Function' function ignores the receiver object when
8334 // called using 'new' and creates a new JSFunction object that
8335 // is returned. The receiver object is only used for error
8336 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008337 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008338 // allocate JSFunctions since it does not properly initialize
8339 // the shared part of the function. Since the receiver is
8340 // ignored anyway, we use the global object as the receiver
8341 // instead of a new JSFunction object. This way, errors are
8342 // reported the same way whether or not 'Function' is called
8343 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008344 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008345 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008346 }
8347
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008348 // The function should be compiled for the optimization hints to be
8349 // available. We cannot use EnsureCompiled because that forces a
8350 // compilation through the shared function info which makes it
8351 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008352 if (!function->is_compiled()) {
8353 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8354 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008355
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008356 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008357 if (!function->has_initial_map() &&
8358 shared->IsInobjectSlackTrackingInProgress()) {
8359 // The tracking is already in progress for another function. We can only
8360 // track one initial_map at a time, so we force the completion before the
8361 // function is called as a constructor for the first time.
8362 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008363 }
8364
8365 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008366 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8367 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008368 // Delay setting the stub if inobject slack tracking is in progress.
8369 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008370 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008371 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008372
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008373 isolate->counters()->constructed_objects()->Increment();
8374 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008375
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008376 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008377}
8378
8379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008380RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008381 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008382 ASSERT(args.length() == 1);
8383
8384 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8385 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008386 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008388 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008389}
8390
8391
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008392RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008393 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008394 ASSERT(args.length() == 1);
8395
8396 Handle<JSFunction> function = args.at<JSFunction>(0);
8397#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008398 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008399 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008400 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 PrintF("]\n");
8402 }
8403#endif
8404
lrn@chromium.org34e60782011-09-15 07:25:40 +00008405 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008406 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008407 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008408 return Failure::Exception();
8409 }
8410
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008411 // All done. Return the compiled code.
8412 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008413 return function->code();
8414}
8415
8416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008417RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008418 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008419 ASSERT(args.length() == 1);
8420 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008421
8422 // If the function is not compiled ignore the lazy
8423 // recompilation. This can happen if the debugger is activated and
8424 // the function is returned to the not compiled state.
8425 if (!function->shared()->is_compiled()) {
8426 function->ReplaceCode(function->shared()->code());
8427 return function->code();
8428 }
8429
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008430 // If the function is not optimizable or debugger is active continue using the
8431 // code from the full compiler.
8432 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008433 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008434 if (FLAG_trace_opt) {
8435 PrintF("[failed to optimize ");
8436 function->PrintName();
8437 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8438 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008439 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008440 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008441 function->ReplaceCode(function->shared()->code());
8442 return function->code();
8443 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008444 if (JSFunction::CompileOptimized(function,
8445 AstNode::kNoNumber,
8446 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008447 return function->code();
8448 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008449 if (FLAG_trace_opt) {
8450 PrintF("[failed to optimize ");
8451 function->PrintName();
8452 PrintF(": optimized compilation failed]\n");
8453 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008454 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008455 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008456}
8457
8458
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008459class ActivationsFinder : public ThreadVisitor {
8460 public:
8461 explicit ActivationsFinder(JSFunction* function)
8462 : function_(function), has_activations_(false) {}
8463
8464 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8465 if (has_activations_) return;
8466
8467 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8468 JavaScriptFrame* frame = it.frame();
8469 if (frame->is_optimized() && frame->function() == function_) {
8470 has_activations_ = true;
8471 return;
8472 }
8473 }
8474 }
8475
8476 bool has_activations() { return has_activations_; }
8477
8478 private:
8479 JSFunction* function_;
8480 bool has_activations_;
8481};
8482
8483
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008484RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008485 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008486 ASSERT(args.length() == 1);
8487 RUNTIME_ASSERT(args[0]->IsSmi());
8488 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008489 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8491 ASSERT(isolate->heap()->IsAllocationAllowed());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008492 int jsframes = deoptimizer->jsframe_count();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008493
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008494 deoptimizer->MaterializeHeapNumbers();
8495 delete deoptimizer;
8496
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008497 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008498 JavaScriptFrame* frame = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008499 for (int i = 0; i < jsframes - 1; i++) it.Advance();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008500 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008501
8502 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008503 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008504 Handle<Object> arguments;
8505 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008506 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008507 if (arguments.is_null()) {
8508 // FunctionGetArguments can't throw an exception, so cast away the
8509 // doubt with an assert.
8510 arguments = Handle<Object>(
8511 Accessors::FunctionGetArguments(*function,
8512 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008513 ASSERT(*arguments != isolate->heap()->null_value());
8514 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008515 }
8516 frame->SetExpression(i, *arguments);
8517 }
8518 }
8519
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008520 if (type == Deoptimizer::EAGER) {
8521 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008522 }
8523
8524 // Avoid doing too much work when running with --always-opt and keep
8525 // the optimized code around.
8526 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008527 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008528 }
8529
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008530 // Find other optimized activations of the function.
8531 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008532 while (!it.done()) {
8533 JavaScriptFrame* frame = it.frame();
8534 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008535 has_other_activations = true;
8536 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008537 }
8538 it.Advance();
8539 }
8540
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008541 if (!has_other_activations) {
8542 ActivationsFinder activations_finder(*function);
8543 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8544 has_other_activations = activations_finder.has_activations();
8545 }
8546
8547 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008548 if (FLAG_trace_deopt) {
8549 PrintF("[removing optimized code for: ");
8550 function->PrintName();
8551 PrintF("]\n");
8552 }
8553 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008554 } else {
8555 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008556 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008557 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008558}
8559
8560
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008561RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008562 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008563 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008564 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008565}
8566
8567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008568RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008569 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008570 ASSERT(args.length() == 1);
8571 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008572 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008573
8574 Deoptimizer::DeoptimizeFunction(*function);
8575
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008576 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008577}
8578
8579
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008580RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8581#if defined(USE_SIMULATOR)
8582 return isolate->heap()->true_value();
8583#else
8584 return isolate->heap()->false_value();
8585#endif
8586}
8587
8588
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008589RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8590 HandleScope scope(isolate);
8591 ASSERT(args.length() == 1);
8592 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8593 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8594 function->MarkForLazyRecompilation();
8595 return isolate->heap()->undefined_value();
8596}
8597
8598
lrn@chromium.org1c092762011-05-09 09:42:16 +00008599RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8600 HandleScope scope(isolate);
8601 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008602 // The least significant bit (after untagging) indicates whether the
8603 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008604 if (!V8::UseCrankshaft()) {
8605 return Smi::FromInt(4); // 4 == "never".
8606 }
8607 if (FLAG_always_opt) {
8608 return Smi::FromInt(3); // 3 == "always".
8609 }
8610 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8611 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8612 : Smi::FromInt(2); // 2 == "no".
8613}
8614
8615
8616RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8617 HandleScope scope(isolate);
8618 ASSERT(args.length() == 1);
8619 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8620 return Smi::FromInt(function->shared()->opt_count());
8621}
8622
8623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008624RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008625 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008626 ASSERT(args.length() == 1);
8627 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8628
8629 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008630 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008631
8632 // We have hit a back edge in an unoptimized frame for a function that was
8633 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008634 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008635 // Keep track of whether we've succeeded in optimizing.
8636 bool succeeded = unoptimized->optimizable();
8637 if (succeeded) {
8638 // If we are trying to do OSR when there are already optimized
8639 // activations of the function, it means (a) the function is directly or
8640 // indirectly recursive and (b) an optimized invocation has been
8641 // deoptimized so that we are currently in an unoptimized activation.
8642 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008643 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008644 while (succeeded && !it.done()) {
8645 JavaScriptFrame* frame = it.frame();
8646 succeeded = !frame->is_optimized() || frame->function() != *function;
8647 it.Advance();
8648 }
8649 }
8650
8651 int ast_id = AstNode::kNoNumber;
8652 if (succeeded) {
8653 // The top JS function is this one, the PC is somewhere in the
8654 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008655 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008656 JavaScriptFrame* frame = it.frame();
8657 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008658 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008659 ASSERT(unoptimized->contains(frame->pc()));
8660
8661 // Use linear search of the unoptimized code's stack check table to find
8662 // the AST id matching the PC.
8663 Address start = unoptimized->instruction_start();
8664 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008665 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008666 uint32_t table_length = Memory::uint32_at(table_cursor);
8667 table_cursor += kIntSize;
8668 for (unsigned i = 0; i < table_length; ++i) {
8669 // Table entries are (AST id, pc offset) pairs.
8670 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8671 if (pc_offset == target_pc_offset) {
8672 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8673 break;
8674 }
8675 table_cursor += 2 * kIntSize;
8676 }
8677 ASSERT(ast_id != AstNode::kNoNumber);
8678 if (FLAG_trace_osr) {
8679 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8680 function->PrintName();
8681 PrintF("]\n");
8682 }
8683
8684 // Try to compile the optimized code. A true return value from
8685 // CompileOptimized means that compilation succeeded, not necessarily
8686 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008687 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008688 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008689 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8690 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008691 if (data->OsrPcOffset()->value() >= 0) {
8692 if (FLAG_trace_osr) {
8693 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008694 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008695 }
8696 ASSERT(data->OsrAstId()->value() == ast_id);
8697 } else {
8698 // We may never generate the desired OSR entry if we emit an
8699 // early deoptimize.
8700 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008701 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008702 } else {
8703 succeeded = false;
8704 }
8705 }
8706
8707 // Revert to the original stack checks in the original unoptimized code.
8708 if (FLAG_trace_osr) {
8709 PrintF("[restoring original stack checks in ");
8710 function->PrintName();
8711 PrintF("]\n");
8712 }
8713 StackCheckStub check_stub;
8714 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008715 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008716 Deoptimizer::RevertStackCheckCode(*unoptimized,
8717 *check_code,
8718 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008719
8720 // Allow OSR only at nesting level zero again.
8721 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8722
8723 // If the optimization attempt succeeded, return the AST id tagged as a
8724 // smi. This tells the builtin that we need to translate the unoptimized
8725 // frame to an optimized one.
8726 if (succeeded) {
8727 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8728 return Smi::FromInt(ast_id);
8729 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008730 if (function->IsMarkedForLazyRecompilation()) {
8731 function->ReplaceCode(function->shared()->code());
8732 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008733 return Smi::FromInt(-1);
8734 }
8735}
8736
8737
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008738RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8739 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8740 return isolate->heap()->undefined_value();
8741}
8742
8743
danno@chromium.orgc612e022011-11-10 11:38:15 +00008744RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8745 HandleScope scope(isolate);
8746 ASSERT(args.length() >= 2);
8747 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8748 Object* receiver = args[0];
8749 int argc = args.length() - 2;
8750
8751 // If there are too many arguments, allocate argv via malloc.
8752 const int argv_small_size = 10;
8753 Handle<Object> argv_small_buffer[argv_small_size];
8754 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8755 Handle<Object>* argv = argv_small_buffer;
8756 if (argc > argv_small_size) {
8757 argv = new Handle<Object>[argc];
8758 if (argv == NULL) return isolate->StackOverflow();
8759 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8760 }
8761
8762 for (int i = 0; i < argc; ++i) {
8763 MaybeObject* maybe = args[1 + i];
8764 Object* object;
8765 if (!maybe->To<Object>(&object)) return maybe;
8766 argv[i] = Handle<Object>(object);
8767 }
8768
8769 bool threw;
8770 Handle<JSReceiver> hfun(fun);
8771 Handle<Object> hreceiver(receiver);
8772 Handle<Object> result =
8773 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8774
8775 if (threw) return Failure::Exception();
8776 return *result;
8777}
8778
8779
lrn@chromium.org34e60782011-09-15 07:25:40 +00008780RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8781 HandleScope scope(isolate);
8782 ASSERT(args.length() == 5);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008783 CONVERT_ARG_CHECKED(JSReceiver, fun, 0);
8784 Handle<Object> receiver = args.at<Object>(1);
8785 CONVERT_ARG_CHECKED(JSObject, arguments, 2);
8786 CONVERT_SMI_ARG_CHECKED(offset, 3);
8787 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008788 ASSERT(offset >= 0);
8789 ASSERT(argc >= 0);
8790
8791 // If there are too many arguments, allocate argv via malloc.
8792 const int argv_small_size = 10;
8793 Handle<Object> argv_small_buffer[argv_small_size];
8794 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8795 Handle<Object>* argv = argv_small_buffer;
8796 if (argc > argv_small_size) {
8797 argv = new Handle<Object>[argc];
8798 if (argv == NULL) return isolate->StackOverflow();
8799 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8800 }
8801
8802 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008803 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008804 }
8805
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008806 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008807 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008808 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008809
8810 if (threw) return Failure::Exception();
8811 return *result;
8812}
8813
8814
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008815RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008816 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008817 ASSERT(args.length() == 1);
8818 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8819 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8820}
8821
8822
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008823RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008824 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008825 ASSERT(args.length() == 1);
8826 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8827 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8828}
8829
8830
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008831RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008832 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008833 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008834
kasper.lund7276f142008-07-30 08:49:36 +00008835 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008836 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008837 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008838 { MaybeObject* maybe_result =
8839 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008840 if (!maybe_result->ToObject(&result)) return maybe_result;
8841 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008842
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008843 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008844
kasper.lund7276f142008-07-30 08:49:36 +00008845 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008846}
8847
lrn@chromium.org303ada72010-10-27 09:33:13 +00008848
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008849RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8850 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008851 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008852 JSObject* extension_object;
8853 if (args[0]->IsJSObject()) {
8854 extension_object = JSObject::cast(args[0]);
8855 } else {
8856 // Convert the object to a proper JavaScript object.
8857 MaybeObject* maybe_js_object = args[0]->ToObject();
8858 if (!maybe_js_object->To(&extension_object)) {
8859 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8860 HandleScope scope(isolate);
8861 Handle<Object> handle = args.at<Object>(0);
8862 Handle<Object> result =
8863 isolate->factory()->NewTypeError("with_expression",
8864 HandleVector(&handle, 1));
8865 return isolate->Throw(*result);
8866 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008867 return maybe_js_object;
8868 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008869 }
8870 }
8871
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008872 JSFunction* function;
8873 if (args[1]->IsSmi()) {
8874 // A smi sentinel indicates a context nested inside global code rather
8875 // than some function. There is a canonical empty function that can be
8876 // gotten from the global context.
8877 function = isolate->context()->global_context()->closure();
8878 } else {
8879 function = JSFunction::cast(args[1]);
8880 }
8881
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008882 Context* context;
8883 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008884 isolate->heap()->AllocateWithContext(function,
8885 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008886 extension_object);
8887 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008888 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008889 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008890}
8891
8892
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008893RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008894 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008895 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008896 String* name = String::cast(args[0]);
8897 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008898 JSFunction* function;
8899 if (args[2]->IsSmi()) {
8900 // A smi sentinel indicates a context nested inside global code rather
8901 // than some function. There is a canonical empty function that can be
8902 // gotten from the global context.
8903 function = isolate->context()->global_context()->closure();
8904 } else {
8905 function = JSFunction::cast(args[2]);
8906 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008907 Context* context;
8908 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008909 isolate->heap()->AllocateCatchContext(function,
8910 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008911 name,
8912 thrown_object);
8913 if (!maybe_context->To(&context)) return maybe_context;
8914 isolate->set_context(context);
8915 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008916}
8917
8918
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008919RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8920 NoHandleAllocation ha;
8921 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008922 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008923 JSFunction* function;
8924 if (args[1]->IsSmi()) {
8925 // A smi sentinel indicates a context nested inside global code rather
8926 // than some function. There is a canonical empty function that can be
8927 // gotten from the global context.
8928 function = isolate->context()->global_context()->closure();
8929 } else {
8930 function = JSFunction::cast(args[1]);
8931 }
8932 Context* context;
8933 MaybeObject* maybe_context =
8934 isolate->heap()->AllocateBlockContext(function,
8935 isolate->context(),
8936 scope_info);
8937 if (!maybe_context->To(&context)) return maybe_context;
8938 isolate->set_context(context);
8939 return context;
8940}
8941
8942
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008943RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008944 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008945 ASSERT(args.length() == 2);
8946
8947 CONVERT_ARG_CHECKED(Context, context, 0);
8948 CONVERT_ARG_CHECKED(String, name, 1);
8949
8950 int index;
8951 PropertyAttributes attributes;
8952 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008953 BindingFlags binding_flags;
8954 Handle<Object> holder = context->Lookup(name,
8955 flags,
8956 &index,
8957 &attributes,
8958 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008959
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008960 // If the slot was not found the result is true.
8961 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008962 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008963 }
8964
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008965 // If the slot was found in a context, it should be DONT_DELETE.
8966 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008967 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008968 }
8969
8970 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008971 // the global object, or the subject of a with. Try to delete it
8972 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008973 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008974 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008975}
8976
8977
ager@chromium.orga1645e22009-09-09 19:27:10 +00008978// A mechanism to return a pair of Object pointers in registers (if possible).
8979// How this is achieved is calling convention-dependent.
8980// All currently supported x86 compiles uses calling conventions that are cdecl
8981// variants where a 64-bit value is returned in two 32-bit registers
8982// (edx:eax on ia32, r1:r0 on ARM).
8983// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8984// In Win64 calling convention, a struct of two pointers is returned in memory,
8985// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008986#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008987struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008988 MaybeObject* x;
8989 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008990};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008991
lrn@chromium.org303ada72010-10-27 09:33:13 +00008992static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008993 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008994 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8995 // In Win64 they are assigned to a hidden first argument.
8996 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008997}
8998#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008999typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009000static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009002 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009003}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009004#endif
9005
9006
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009007static inline MaybeObject* Unhole(Heap* heap,
9008 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009009 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009010 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
9011 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009012 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009013}
9014
9015
danno@chromium.org40cb8782011-05-25 07:58:50 +00009016static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9017 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009018 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009019 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009020 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009021 JSFunction* context_extension_function =
9022 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009023 // If the holder isn't a context extension object, we just return it
9024 // as the receiver. This allows arguments objects to be used as
9025 // receivers, but only if they are put in the context scope chain
9026 // explicitly via a with-statement.
9027 Object* constructor = holder->map()->constructor();
9028 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00009029 // Fall back to using the global object as the implicit receiver if
9030 // the property turns out to be a local variable allocated in a
9031 // context extension object - introduced via eval. Implicit global
9032 // receivers are indicated with the hole value.
9033 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009034}
9035
9036
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009037static ObjectPair LoadContextSlotHelper(Arguments args,
9038 Isolate* isolate,
9039 bool throw_error) {
9040 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009041 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009042
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009043 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009044 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009045 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009046 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009047 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009048
9049 int index;
9050 PropertyAttributes attributes;
9051 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009052 BindingFlags binding_flags;
9053 Handle<Object> holder = context->Lookup(name,
9054 flags,
9055 &index,
9056 &attributes,
9057 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009058
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009059 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009060 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009061 ASSERT(holder->IsContext());
9062 // If the "property" we were looking for is a local variable, the
9063 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009064 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009065 // Use the hole as the receiver to signal that the receiver is implicit
9066 // and that the global receiver should be used (as distinguished from an
9067 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009068 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009069 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009070 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009071 switch (binding_flags) {
9072 case MUTABLE_CHECK_INITIALIZED:
9073 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9074 if (value->IsTheHole()) {
9075 Handle<Object> reference_error =
9076 isolate->factory()->NewReferenceError("not_defined",
9077 HandleVector(&name, 1));
9078 return MakePair(isolate->Throw(*reference_error), NULL);
9079 }
9080 // FALLTHROUGH
9081 case MUTABLE_IS_INITIALIZED:
9082 case IMMUTABLE_IS_INITIALIZED:
9083 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9084 ASSERT(!value->IsTheHole());
9085 return MakePair(value, *receiver);
9086 case IMMUTABLE_CHECK_INITIALIZED:
9087 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9088 case MISSING_BINDING:
9089 UNREACHABLE();
9090 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009091 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009092 }
9093
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009094 // Otherwise, if the slot was found the holder is a context extension
9095 // object, subject of a with, or a global object. We read the named
9096 // property from it.
9097 if (!holder.is_null()) {
9098 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9099 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009100 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009101 Handle<Object> receiver_handle(object->IsGlobalObject()
9102 ? GlobalObject::cast(*object)->global_receiver()
9103 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009104
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009105 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009106 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009107 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009108 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009109 }
9110
9111 if (throw_error) {
9112 // The property doesn't exist - throw exception.
9113 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009114 isolate->factory()->NewReferenceError("not_defined",
9115 HandleVector(&name, 1));
9116 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009117 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009118 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009119 return MakePair(isolate->heap()->undefined_value(),
9120 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009121 }
9122}
9123
9124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009125RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009126 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009127}
9128
9129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009130RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009131 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009132}
9133
9134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009135RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009136 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009137 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009139 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009140 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009141 CONVERT_ARG_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009142 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9143 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9144 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009145
9146 int index;
9147 PropertyAttributes attributes;
9148 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009149 BindingFlags binding_flags;
9150 Handle<Object> holder = context->Lookup(name,
9151 flags,
9152 &index,
9153 &attributes,
9154 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155
9156 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009157 // The property was found in a context slot.
9158 Handle<Context> context = Handle<Context>::cast(holder);
9159 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9160 context->get(index)->IsTheHole()) {
9161 Handle<Object> error =
9162 isolate->factory()->NewReferenceError("not_defined",
9163 HandleVector(&name, 1));
9164 return isolate->Throw(*error);
9165 }
9166 // Ignore if read_only variable.
9167 if ((attributes & READ_ONLY) == 0) {
9168 // Context is a fixed array and set cannot fail.
9169 context->set(index, *value);
9170 } else if (strict_mode == kStrictMode) {
9171 // Setting read only property in strict mode.
9172 Handle<Object> error =
9173 isolate->factory()->NewTypeError("strict_cannot_assign",
9174 HandleVector(&name, 1));
9175 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009176 }
9177 return *value;
9178 }
9179
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009180 // Slow case: The property is not in a context slot. It is either in a
9181 // context extension object, a property of the subject of a with, or a
9182 // property of the global object.
9183 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009184
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009185 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009186 // The property exists on the holder.
9187 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009188 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009189 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009190 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009191
9192 if (strict_mode == kStrictMode) {
9193 // Throw in strict mode (assignment to undefined variable).
9194 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009195 isolate->factory()->NewReferenceError(
9196 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009197 return isolate->Throw(*error);
9198 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009199 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009200 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009201 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009202 }
9203
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009204 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009205 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009206 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009207 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009208 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009209 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009210 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009211 // Setting read only property in strict mode.
9212 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009213 isolate->factory()->NewTypeError(
9214 "strict_cannot_assign", HandleVector(&name, 1));
9215 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009216 }
9217 return *value;
9218}
9219
9220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009221RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009222 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009223 ASSERT(args.length() == 1);
9224
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009225 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009226}
9227
9228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009229RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009230 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009231 ASSERT(args.length() == 1);
9232
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009233 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234}
9235
9236
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009237RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009238 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009239 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009240}
9241
9242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009243RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009244 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009245 ASSERT(args.length() == 1);
9246
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009247 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009248 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009249 isolate->factory()->NewReferenceError("not_defined",
9250 HandleVector(&name, 1));
9251 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252}
9253
9254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009255RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009256 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009257
9258 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009259 if (isolate->stack_guard()->IsStackOverflow()) {
9260 NoHandleAllocation na;
9261 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009262 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009263
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009264 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009265}
9266
9267
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009268static int StackSize() {
9269 int n = 0;
9270 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9271 return n;
9272}
9273
9274
9275static void PrintTransition(Object* result) {
9276 // indentation
9277 { const int nmax = 80;
9278 int n = StackSize();
9279 if (n <= nmax)
9280 PrintF("%4d:%*s", n, n, "");
9281 else
9282 PrintF("%4d:%*s", n, nmax, "...");
9283 }
9284
9285 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009286 JavaScriptFrame::PrintTop(stdout, true, false);
9287 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009288 } else {
9289 // function result
9290 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009291 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009292 PrintF("\n");
9293 }
9294}
9295
9296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009297RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009298 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009299 NoHandleAllocation ha;
9300 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009301 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009302}
9303
9304
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009305RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009306 NoHandleAllocation ha;
9307 PrintTransition(args[0]);
9308 return args[0]; // return TOS
9309}
9310
9311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009312RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009313 NoHandleAllocation ha;
9314 ASSERT(args.length() == 1);
9315
9316#ifdef DEBUG
9317 if (args[0]->IsString()) {
9318 // If we have a string, assume it's a code "marker"
9319 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009320 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009321 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009322 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9323 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009324 } else {
9325 PrintF("DebugPrint: ");
9326 }
9327 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009328 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009329 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009330 HeapObject::cast(args[0])->map()->Print();
9331 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009333 // ShortPrint is available in release mode. Print is not.
9334 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009335#endif
9336 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009337 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009338
9339 return args[0]; // return TOS
9340}
9341
9342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009343RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009344 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009345 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009346 isolate->PrintStack();
9347 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009348}
9349
9350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009351RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009352 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009353 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009354
9355 // According to ECMA-262, section 15.9.1, page 117, the precision of
9356 // the number in a Date object representing a particular instant in
9357 // time is milliseconds. Therefore, we floor the result of getting
9358 // the OS time.
9359 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009360 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009361}
9362
9363
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009364RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009365 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009366 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009367
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009368 CONVERT_ARG_CHECKED(String, str, 0);
9369 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009370
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009371 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009372
9373 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009374 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009375 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009376 RUNTIME_ASSERT(output->HasFastElements());
9377
9378 AssertNoAllocation no_allocation;
9379
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009380 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009381 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9382 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009383 String::FlatContent str_content = str->GetFlatContent();
9384 if (str_content.IsAscii()) {
9385 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009386 output_array,
9387 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009388 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009389 ASSERT(str_content.IsTwoByte());
9390 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009391 output_array,
9392 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009393 }
9394
9395 if (result) {
9396 return *output;
9397 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009398 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009399 }
9400}
9401
9402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009403RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009404 NoHandleAllocation ha;
9405 ASSERT(args.length() == 1);
9406
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009407 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009408 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009409 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009410}
9411
9412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009413RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009414 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009415 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009416
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009417 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009418}
9419
9420
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009421RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009422 NoHandleAllocation ha;
9423 ASSERT(args.length() == 1);
9424
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009425 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009426 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009427}
9428
9429
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009430RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009431 ASSERT(args.length() == 1);
9432 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009433 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009434 return JSGlobalObject::cast(global)->global_receiver();
9435}
9436
9437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009438RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009439 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009440 ASSERT_EQ(1, args.length());
9441 CONVERT_ARG_CHECKED(String, source, 0);
9442
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009443 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009444 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009445 Handle<Object> result;
9446 if (source->IsSeqAsciiString()) {
9447 result = JsonParser<true>::Parse(source);
9448 } else {
9449 result = JsonParser<false>::Parse(source);
9450 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009451 if (result.is_null()) {
9452 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009453 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009454 return Failure::Exception();
9455 }
9456 return *result;
9457}
9458
9459
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009460bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9461 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009462 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9463 // Check with callback if set.
9464 AllowCodeGenerationFromStringsCallback callback =
9465 isolate->allow_code_gen_callback();
9466 if (callback == NULL) {
9467 // No callback set and code generation disallowed.
9468 return false;
9469 } else {
9470 // Callback set. Let it decide if code generation is allowed.
9471 VMState state(isolate, EXTERNAL);
9472 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009473 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009474}
9475
9476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009477RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009478 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009479 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009480 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009481
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009482 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009483 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009484
9485 // Check if global context allows code generation from
9486 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009487 if (context->allow_code_gen_from_strings()->IsFalse() &&
9488 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009489 return isolate->Throw(*isolate->factory()->NewError(
9490 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9491 }
9492
9493 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009494 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009495 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009496 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009497 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009498 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9499 context,
9500 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009501 return *fun;
9502}
9503
9504
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009505static ObjectPair CompileGlobalEval(Isolate* isolate,
9506 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009507 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009508 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009509 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009510 Handle<Context> context = Handle<Context>(isolate->context());
9511 Handle<Context> global_context = Handle<Context>(context->global_context());
9512
9513 // Check if global context allows code generation from
9514 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009515 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9516 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009517 isolate->Throw(*isolate->factory()->NewError(
9518 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9519 return MakePair(Failure::Exception(), NULL);
9520 }
9521
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009522 // Deal with a normal eval call with a string argument. Compile it
9523 // and return the compiled function bound in the local context.
9524 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9525 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009526 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009527 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009528 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009529 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009530 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009531 Handle<JSFunction> compiled =
9532 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009533 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009534 return MakePair(*compiled, *receiver);
9535}
9536
9537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009538RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009539 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009540
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009541 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009542 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009543
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009544 // If "eval" didn't refer to the original GlobalEval, it's not a
9545 // direct call to eval.
9546 // (And even if it is, but the first argument isn't a string, just let
9547 // execution default to an indirect call to eval, which will also return
9548 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009549 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009550 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009551 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009552 }
9553
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009554 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009555 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009556 return CompileGlobalEval(isolate,
9557 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009558 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009559 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009560 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009561}
9562
9563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009564RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009565 // This utility adjusts the property attributes for newly created Function
9566 // object ("new Function(...)") by changing the map.
9567 // All it does is changing the prototype property to enumerable
9568 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009569 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009570 ASSERT(args.length() == 1);
9571 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009572
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009573 Handle<Map> map = func->shared()->is_classic_mode()
9574 ? isolate->function_instance_map()
9575 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009576
9577 ASSERT(func->map()->instance_type() == map->instance_type());
9578 ASSERT(func->map()->instance_size() == map->instance_size());
9579 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009580 return *func;
9581}
9582
9583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009584RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009585 // Allocate a block of memory in NewSpace (filled with a filler).
9586 // Use as fallback for allocation in generated code when NewSpace
9587 // is full.
9588 ASSERT(args.length() == 1);
9589 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9590 int size = size_smi->value();
9591 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9592 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009593 Heap* heap = isolate->heap();
9594 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009595 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009596 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009597 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009598 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009599 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009600 }
9601 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009602 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009603}
9604
9605
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009606// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009607// array. Returns true if the element was pushed on the stack and
9608// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009609RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009610 ASSERT(args.length() == 2);
9611 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009612 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009613 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009614 int length = Smi::cast(array->length())->value();
9615 FixedArray* elements = FixedArray::cast(array->elements());
9616 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009617 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009618 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009619 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009620 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009621 { MaybeObject* maybe_obj =
9622 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009623 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9624 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009625 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009626}
9627
9628
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009629/**
9630 * A simple visitor visits every element of Array's.
9631 * The backend storage can be a fixed array for fast elements case,
9632 * or a dictionary for sparse array. Since Dictionary is a subtype
9633 * of FixedArray, the class can be used by both fast and slow cases.
9634 * The second parameter of the constructor, fast_elements, specifies
9635 * whether the storage is a FixedArray or Dictionary.
9636 *
9637 * An index limit is used to deal with the situation that a result array
9638 * length overflows 32-bit non-negative integer.
9639 */
9640class ArrayConcatVisitor {
9641 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009642 ArrayConcatVisitor(Isolate* isolate,
9643 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009644 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009645 isolate_(isolate),
9646 storage_(Handle<FixedArray>::cast(
9647 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009648 index_offset_(0u),
9649 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009650
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009651 ~ArrayConcatVisitor() {
9652 clear_storage();
9653 }
9654
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009655 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009656 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009657 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009658
9659 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009660 if (index < static_cast<uint32_t>(storage_->length())) {
9661 storage_->set(index, *elm);
9662 return;
9663 }
9664 // Our initial estimate of length was foiled, possibly by
9665 // getters on the arrays increasing the length of later arrays
9666 // during iteration.
9667 // This shouldn't happen in anything but pathological cases.
9668 SetDictionaryMode(index);
9669 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009670 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009671 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009672 Handle<SeededNumberDictionary> dict(
9673 SeededNumberDictionary::cast(*storage_));
9674 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009675 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009676 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009677 // Dictionary needed to grow.
9678 clear_storage();
9679 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009680 }
9681}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009682
9683 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009684 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9685 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009686 } else {
9687 index_offset_ += delta;
9688 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009689 }
9690
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009691 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009692 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009693 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009694 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009695 Handle<Map> map;
9696 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009697 map = isolate_->factory()->GetElementsTransitionMap(array,
9698 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009699 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009700 map = isolate_->factory()->GetElementsTransitionMap(array,
9701 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009702 }
9703 array->set_map(*map);
9704 array->set_length(*length);
9705 array->set_elements(*storage_);
9706 return array;
9707 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009708
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009709 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009710 // Convert storage to dictionary mode.
9711 void SetDictionaryMode(uint32_t index) {
9712 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009713 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009714 Handle<SeededNumberDictionary> slow_storage(
9715 isolate_->factory()->NewSeededNumberDictionary(
9716 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009717 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9718 for (uint32_t i = 0; i < current_length; i++) {
9719 HandleScope loop_scope;
9720 Handle<Object> element(current_storage->get(i));
9721 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009722 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009723 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009724 if (!new_storage.is_identical_to(slow_storage)) {
9725 slow_storage = loop_scope.CloseAndEscape(new_storage);
9726 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009727 }
9728 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009729 clear_storage();
9730 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009731 fast_elements_ = false;
9732 }
9733
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009734 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009735 isolate_->global_handles()->Destroy(
9736 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009737 }
9738
9739 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009740 storage_ = Handle<FixedArray>::cast(
9741 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009742 }
9743
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009744 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009745 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009746 // Index after last seen index. Always less than or equal to
9747 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009748 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009749 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009750};
9751
9752
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009753static uint32_t EstimateElementCount(Handle<JSArray> array) {
9754 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9755 int element_count = 0;
9756 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009757 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009758 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009759 // Fast elements can't have lengths that are not representable by
9760 // a 32-bit signed integer.
9761 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9762 int fast_length = static_cast<int>(length);
9763 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9764 for (int i = 0; i < fast_length; i++) {
9765 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009766 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009767 break;
9768 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009769 case FAST_DOUBLE_ELEMENTS:
9770 // TODO(1810): Decide if it's worthwhile to implement this.
9771 UNREACHABLE();
9772 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009773 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009774 Handle<SeededNumberDictionary> dictionary(
9775 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009776 int capacity = dictionary->Capacity();
9777 for (int i = 0; i < capacity; i++) {
9778 Handle<Object> key(dictionary->KeyAt(i));
9779 if (dictionary->IsKey(*key)) {
9780 element_count++;
9781 }
9782 }
9783 break;
9784 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009785 case NON_STRICT_ARGUMENTS_ELEMENTS:
9786 case EXTERNAL_BYTE_ELEMENTS:
9787 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9788 case EXTERNAL_SHORT_ELEMENTS:
9789 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9790 case EXTERNAL_INT_ELEMENTS:
9791 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9792 case EXTERNAL_FLOAT_ELEMENTS:
9793 case EXTERNAL_DOUBLE_ELEMENTS:
9794 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009795 // External arrays are always dense.
9796 return length;
9797 }
9798 // As an estimate, we assume that the prototype doesn't contain any
9799 // inherited elements.
9800 return element_count;
9801}
9802
9803
9804
9805template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009806static void IterateExternalArrayElements(Isolate* isolate,
9807 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009808 bool elements_are_ints,
9809 bool elements_are_guaranteed_smis,
9810 ArrayConcatVisitor* visitor) {
9811 Handle<ExternalArrayClass> array(
9812 ExternalArrayClass::cast(receiver->elements()));
9813 uint32_t len = static_cast<uint32_t>(array->length());
9814
9815 ASSERT(visitor != NULL);
9816 if (elements_are_ints) {
9817 if (elements_are_guaranteed_smis) {
9818 for (uint32_t j = 0; j < len; j++) {
9819 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009820 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009821 visitor->visit(j, e);
9822 }
9823 } else {
9824 for (uint32_t j = 0; j < len; j++) {
9825 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009826 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009827 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9828 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9829 visitor->visit(j, e);
9830 } else {
9831 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009832 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009833 visitor->visit(j, e);
9834 }
9835 }
9836 }
9837 } else {
9838 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009839 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009840 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009841 visitor->visit(j, e);
9842 }
9843 }
9844}
9845
9846
9847// Used for sorting indices in a List<uint32_t>.
9848static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9849 uint32_t a = *ap;
9850 uint32_t b = *bp;
9851 return (a == b) ? 0 : (a < b) ? -1 : 1;
9852}
9853
9854
9855static void CollectElementIndices(Handle<JSObject> object,
9856 uint32_t range,
9857 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009858 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009859 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009860 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009861 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009862 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9863 uint32_t length = static_cast<uint32_t>(elements->length());
9864 if (range < length) length = range;
9865 for (uint32_t i = 0; i < length; i++) {
9866 if (!elements->get(i)->IsTheHole()) {
9867 indices->Add(i);
9868 }
9869 }
9870 break;
9871 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009872 case FAST_DOUBLE_ELEMENTS: {
9873 // TODO(1810): Decide if it's worthwhile to implement this.
9874 UNREACHABLE();
9875 break;
9876 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009877 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009878 Handle<SeededNumberDictionary> dict(
9879 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009880 uint32_t capacity = dict->Capacity();
9881 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009882 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009883 Handle<Object> k(dict->KeyAt(j));
9884 if (dict->IsKey(*k)) {
9885 ASSERT(k->IsNumber());
9886 uint32_t index = static_cast<uint32_t>(k->Number());
9887 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009888 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009889 }
9890 }
9891 }
9892 break;
9893 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009894 default: {
9895 int dense_elements_length;
9896 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009897 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009898 dense_elements_length =
9899 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009900 break;
9901 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009902 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009903 dense_elements_length =
9904 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009905 break;
9906 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009907 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009908 dense_elements_length =
9909 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009910 break;
9911 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009912 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009913 dense_elements_length =
9914 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009915 break;
9916 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009917 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009918 dense_elements_length =
9919 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009920 break;
9921 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009922 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009923 dense_elements_length =
9924 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009925 break;
9926 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009927 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009928 dense_elements_length =
9929 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009930 break;
9931 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009932 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009933 dense_elements_length =
9934 ExternalFloatArray::cast(object->elements())->length();
9935 break;
9936 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009937 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009938 dense_elements_length =
9939 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009940 break;
9941 }
9942 default:
9943 UNREACHABLE();
9944 dense_elements_length = 0;
9945 break;
9946 }
9947 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9948 if (range <= length) {
9949 length = range;
9950 // We will add all indices, so we might as well clear it first
9951 // and avoid duplicates.
9952 indices->Clear();
9953 }
9954 for (uint32_t i = 0; i < length; i++) {
9955 indices->Add(i);
9956 }
9957 if (length == range) return; // All indices accounted for already.
9958 break;
9959 }
9960 }
9961
9962 Handle<Object> prototype(object->GetPrototype());
9963 if (prototype->IsJSObject()) {
9964 // The prototype will usually have no inherited element indices,
9965 // but we have to check.
9966 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9967 }
9968}
9969
9970
9971/**
9972 * A helper function that visits elements of a JSArray in numerical
9973 * order.
9974 *
9975 * The visitor argument called for each existing element in the array
9976 * with the element index and the element's value.
9977 * Afterwards it increments the base-index of the visitor by the array
9978 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009979 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009980 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009981static bool IterateElements(Isolate* isolate,
9982 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009983 ArrayConcatVisitor* visitor) {
9984 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9985 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009986 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009987 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009988 // Run through the elements FixedArray and use HasElement and GetElement
9989 // to check the prototype for missing elements.
9990 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9991 int fast_length = static_cast<int>(length);
9992 ASSERT(fast_length <= elements->length());
9993 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009994 HandleScope loop_scope(isolate);
9995 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009996 if (!element_value->IsTheHole()) {
9997 visitor->visit(j, element_value);
9998 } else if (receiver->HasElement(j)) {
9999 // Call GetElement on receiver, not its prototype, or getters won't
10000 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010001 element_value = Object::GetElement(receiver, j);
10002 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010003 visitor->visit(j, element_value);
10004 }
10005 }
10006 break;
10007 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010008 case FAST_DOUBLE_ELEMENTS: {
10009 // TODO(1810): Decide if it's worthwhile to implement this.
10010 UNREACHABLE();
10011 break;
10012 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010013 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010014 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010015 List<uint32_t> indices(dict->Capacity() / 2);
10016 // Collect all indices in the object and the prototypes less
10017 // than length. This might introduce duplicates in the indices list.
10018 CollectElementIndices(receiver, length, &indices);
10019 indices.Sort(&compareUInt32);
10020 int j = 0;
10021 int n = indices.length();
10022 while (j < n) {
10023 HandleScope loop_scope;
10024 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010025 Handle<Object> element = Object::GetElement(receiver, index);
10026 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010027 visitor->visit(index, element);
10028 // Skip to next different index (i.e., omit duplicates).
10029 do {
10030 j++;
10031 } while (j < n && indices[j] == index);
10032 }
10033 break;
10034 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010035 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010036 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10037 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010038 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010039 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010040 visitor->visit(j, e);
10041 }
10042 break;
10043 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010044 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010045 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010046 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010047 break;
10048 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010049 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010050 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010051 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010052 break;
10053 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010054 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010055 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010056 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010057 break;
10058 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010059 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010060 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010061 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010062 break;
10063 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010064 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010065 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010066 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010067 break;
10068 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010069 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010070 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010071 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010072 break;
10073 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010074 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010075 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010076 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010077 break;
10078 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010079 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010080 IterateExternalArrayElements<ExternalDoubleArray, double>(
10081 isolate, receiver, false, false, visitor);
10082 break;
10083 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010084 default:
10085 UNREACHABLE();
10086 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010087 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010088 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010089 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010090}
10091
10092
10093/**
10094 * Array::concat implementation.
10095 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010096 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010097 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010098 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010099RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010100 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010101 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010102
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010103 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10104 int argument_count = static_cast<int>(arguments->length()->Number());
10105 RUNTIME_ASSERT(arguments->HasFastElements());
10106 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010107
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010108 // Pass 1: estimate the length and number of elements of the result.
10109 // The actual length can be larger if any of the arguments have getters
10110 // that mutate other arguments (but will otherwise be precise).
10111 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010112
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010113 uint32_t estimate_result_length = 0;
10114 uint32_t estimate_nof_elements = 0;
10115 {
10116 for (int i = 0; i < argument_count; i++) {
10117 HandleScope loop_scope;
10118 Handle<Object> obj(elements->get(i));
10119 uint32_t length_estimate;
10120 uint32_t element_estimate;
10121 if (obj->IsJSArray()) {
10122 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010123 // TODO(1810): Find out if it's worthwhile to properly support
10124 // arbitrary ElementsKinds. For now, pessimistically transition to
10125 // FAST_ELEMENTS.
10126 if (array->HasFastDoubleElements()) {
10127 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010128 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010129 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010130 length_estimate =
10131 static_cast<uint32_t>(array->length()->Number());
10132 element_estimate =
10133 EstimateElementCount(array);
10134 } else {
10135 length_estimate = 1;
10136 element_estimate = 1;
10137 }
10138 // Avoid overflows by capping at kMaxElementCount.
10139 if (JSObject::kMaxElementCount - estimate_result_length <
10140 length_estimate) {
10141 estimate_result_length = JSObject::kMaxElementCount;
10142 } else {
10143 estimate_result_length += length_estimate;
10144 }
10145 if (JSObject::kMaxElementCount - estimate_nof_elements <
10146 element_estimate) {
10147 estimate_nof_elements = JSObject::kMaxElementCount;
10148 } else {
10149 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010150 }
10151 }
10152 }
10153
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010154 // If estimated number of elements is more than half of length, a
10155 // fixed array (fast case) is more time and space-efficient than a
10156 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010157 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010158
10159 Handle<FixedArray> storage;
10160 if (fast_case) {
10161 // The backing storage array must have non-existing elements to
10162 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010163 storage = isolate->factory()->NewFixedArrayWithHoles(
10164 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010165 } else {
10166 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10167 uint32_t at_least_space_for = estimate_nof_elements +
10168 (estimate_nof_elements >> 2);
10169 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010170 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010171 }
10172
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010173 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010174
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010175 for (int i = 0; i < argument_count; i++) {
10176 Handle<Object> obj(elements->get(i));
10177 if (obj->IsJSArray()) {
10178 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010179 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010180 return Failure::Exception();
10181 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010182 } else {
10183 visitor.visit(0, obj);
10184 visitor.increase_index_offset(1);
10185 }
10186 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010187
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010188 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010189}
10190
10191
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010192// This will not allocate (flatten the string), but it may run
10193// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010194RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010195 NoHandleAllocation ha;
10196 ASSERT(args.length() == 1);
10197
10198 CONVERT_CHECKED(String, string, args[0]);
10199 StringInputBuffer buffer(string);
10200 while (buffer.has_more()) {
10201 uint16_t character = buffer.GetNext();
10202 PrintF("%c", character);
10203 }
10204 return string;
10205}
10206
ager@chromium.org5ec48922009-05-05 07:25:34 +000010207// Moves all own elements of an object, that are below a limit, to positions
10208// starting at zero. All undefined values are placed after non-undefined values,
10209// and are followed by non-existing element. Does not change the length
10210// property.
10211// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010212RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010213 ASSERT(args.length() == 2);
10214 CONVERT_CHECKED(JSObject, object, args[0]);
10215 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10216 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010217}
10218
10219
10220// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010221RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010222 ASSERT(args.length() == 2);
10223 CONVERT_CHECKED(JSArray, from, args[0]);
10224 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010225 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010226 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010227 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010228 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10229 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010230 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010231 } else if (new_elements->map() ==
10232 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010233 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010234 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010235 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010236 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010237 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010238 Object* new_map;
10239 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010240 to->set_map(Map::cast(new_map));
10241 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010242 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010243 Object* obj;
10244 { MaybeObject* maybe_obj = from->ResetElements();
10245 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10246 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010247 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010248 return to;
10249}
10250
10251
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010252// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010253RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010254 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010255 CONVERT_CHECKED(JSObject, object, args[0]);
10256 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010257 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010258 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10259 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010260 } else if (object->IsJSArray()) {
10261 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010262 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010263 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264 }
10265}
10266
10267
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010268RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010269 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010270
10271 ASSERT_EQ(3, args.length());
10272
ager@chromium.orgac091b72010-05-05 07:34:42 +000010273 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010274 Handle<Object> key1 = args.at<Object>(1);
10275 Handle<Object> key2 = args.at<Object>(2);
10276
10277 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010278 if (!key1->ToArrayIndex(&index1)
10279 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010280 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010281 }
10282
ager@chromium.orgac091b72010-05-05 07:34:42 +000010283 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010284 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010285 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010286 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010287 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010288
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010289 RETURN_IF_EMPTY_HANDLE(
10290 isolate, JSObject::SetElement(jsobject, index1, tmp2, kStrictMode));
10291 RETURN_IF_EMPTY_HANDLE(
10292 isolate, JSObject::SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010293
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010294 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010295}
10296
10297
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010299// might have elements. Can either return keys (positive integers) or
10300// intervals (pair of a negative integer (-start-1) followed by a
10301// positive (length)) or undefined values.
10302// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010303RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010304 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010305 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010306 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010307 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010308 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010309 // Create an array and get all the keys into it, then remove all the
10310 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010311 bool threw = false;
10312 Handle<FixedArray> keys =
10313 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10314 if (threw) return Failure::Exception();
10315
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010316 int keys_length = keys->length();
10317 for (int i = 0; i < keys_length; i++) {
10318 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010319 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010320 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010321 // Zap invalid keys.
10322 keys->set_undefined(i);
10323 }
10324 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010325 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010326 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010327 ASSERT(array->HasFastElements() ||
10328 array->HasFastSmiOnlyElements() ||
10329 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010330 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010331 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010332 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010333 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010334 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010335 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010336 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010337 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010338 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010339 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010340 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010341 }
10342}
10343
10344
10345// DefineAccessor takes an optional final argument which is the
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010346// property attributes (e.g. DONT_ENUM, DONT_DELETE). IMPORTANT: due
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010347// to the way accessors are implemented, it is set for both the getter
10348// and setter on the first call to DefineAccessor and ignored on
10349// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010350RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010351 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10352 // Compute attributes.
10353 PropertyAttributes attributes = NONE;
10354 if (args.length() == 5) {
10355 CONVERT_CHECKED(Smi, attrs, args[4]);
10356 int value = attrs->value();
10357 // Only attribute bits should be set.
10358 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10359 attributes = static_cast<PropertyAttributes>(value);
10360 }
10361
10362 CONVERT_CHECKED(JSObject, obj, args[0]);
10363 CONVERT_CHECKED(String, name, args[1]);
10364 CONVERT_CHECKED(Smi, flag, args[2]);
10365 CONVERT_CHECKED(JSFunction, fun, args[3]);
10366 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10367}
10368
10369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010370RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010371 ASSERT(args.length() == 3);
10372 CONVERT_CHECKED(JSObject, obj, args[0]);
10373 CONVERT_CHECKED(String, name, args[1]);
10374 CONVERT_CHECKED(Smi, flag, args[2]);
10375 return obj->LookupAccessor(name, flag->value() == 0);
10376}
10377
10378
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010379#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010380RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010381 ASSERT(args.length() == 0);
10382 return Execution::DebugBreakHelper();
10383}
10384
10385
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010386// Helper functions for wrapping and unwrapping stack frame ids.
10387static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010388 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010389 return Smi::FromInt(id >> 2);
10390}
10391
10392
10393static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10394 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10395}
10396
10397
10398// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010399// args[0]: debug event listener function to set or null or undefined for
10400// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010401// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010402RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010403 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010404 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10405 args[0]->IsUndefined() ||
10406 args[0]->IsNull());
10407 Handle<Object> callback = args.at<Object>(0);
10408 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010409 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010410
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010411 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010412}
10413
10414
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010415RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010416 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010417 isolate->stack_guard()->DebugBreak();
10418 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010419}
10420
10421
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010422static MaybeObject* DebugLookupResultValue(Heap* heap,
10423 Object* receiver,
10424 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010425 LookupResult* result,
10426 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010427 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010428 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010429 case NORMAL:
10430 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010431 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010432 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010433 }
10434 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010435 case FIELD:
10436 value =
10437 JSObject::cast(
10438 result->holder())->FastPropertyAt(result->GetFieldIndex());
10439 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010440 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010441 }
10442 return value;
10443 case CONSTANT_FUNCTION:
10444 return result->GetConstantFunction();
10445 case CALLBACKS: {
10446 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010447 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010448 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10449 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010450 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010451 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010452 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010453 maybe_value = heap->isolate()->pending_exception();
10454 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010455 if (caught_exception != NULL) {
10456 *caught_exception = true;
10457 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010458 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010459 }
10460 return value;
10461 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010462 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010463 }
10464 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010465 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010466 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010467 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010468 case CONSTANT_TRANSITION:
10469 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010470 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010471 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010472 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010473 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010474 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010475 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010476 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010477}
10478
10479
ager@chromium.org32912102009-01-16 10:38:43 +000010480// Get debugger related details for an object property.
10481// args[0]: object holding property
10482// args[1]: name of the property
10483//
10484// The array returned contains the following information:
10485// 0: Property value
10486// 1: Property details
10487// 2: Property value is exception
10488// 3: Getter function if defined
10489// 4: Setter function if defined
10490// Items 2-4 are only filled if the property has either a getter or a setter
10491// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010492RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010493 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010494
10495 ASSERT(args.length() == 2);
10496
10497 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10498 CONVERT_ARG_CHECKED(String, name, 1);
10499
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010500 // Make sure to set the current context to the context before the debugger was
10501 // entered (if the debugger is entered). The reason for switching context here
10502 // is that for some property lookups (accessors and interceptors) callbacks
10503 // into the embedding application can occour, and the embedding application
10504 // could have the assumption that its own global context is the current
10505 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010506 SaveContext save(isolate);
10507 if (isolate->debug()->InDebugger()) {
10508 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010509 }
10510
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010511 // Skip the global proxy as it has no properties and always delegates to the
10512 // real global object.
10513 if (obj->IsJSGlobalProxy()) {
10514 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10515 }
10516
10517
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518 // Check if the name is trivially convertible to an index and get the element
10519 // if so.
10520 uint32_t index;
10521 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010522 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010523 Object* element_or_char;
10524 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010525 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010526 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10527 return maybe_element_or_char;
10528 }
10529 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010530 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010531 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010532 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010533 }
10534
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010535 // Find the number of objects making up this.
10536 int length = LocalPrototypeChainLength(*obj);
10537
10538 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010539 Handle<JSObject> jsproto = obj;
10540 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010541 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010542 jsproto->LocalLookup(*name, &result);
10543 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010544 // LookupResult is not GC safe as it holds raw object pointers.
10545 // GC can happen later in this code so put the required fields into
10546 // local variables using handles when required for later use.
10547 PropertyType result_type = result.type();
10548 Handle<Object> result_callback_obj;
10549 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010550 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10551 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010552 }
10553 Smi* property_details = result.GetPropertyDetails().AsSmi();
10554 // DebugLookupResultValue can cause GC so details from LookupResult needs
10555 // to be copied to handles before this.
10556 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010557 Object* raw_value;
10558 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010559 DebugLookupResultValue(isolate->heap(), *obj, *name,
10560 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010561 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10562 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010563 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010564
10565 // If the callback object is a fixed array then it contains JavaScript
10566 // getter and/or setter.
10567 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010568 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010569 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010570 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010571 details->set(0, *value);
10572 details->set(1, property_details);
10573 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010574 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010575 details->set(3, AccessorPair::cast(*result_callback_obj)->getter());
10576 details->set(4, AccessorPair::cast(*result_callback_obj)->setter());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010577 }
10578
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010579 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010580 }
10581 if (i < length - 1) {
10582 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10583 }
10584 }
10585
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010586 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010587}
10588
10589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010590RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010591 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010592
10593 ASSERT(args.length() == 2);
10594
10595 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10596 CONVERT_ARG_CHECKED(String, name, 1);
10597
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010598 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010599 obj->Lookup(*name, &result);
10600 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010601 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010602 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010603 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010604}
10605
10606
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607// Return the property type calculated from the property details.
10608// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010609RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010610 ASSERT(args.length() == 1);
10611 CONVERT_CHECKED(Smi, details, args[0]);
10612 PropertyType type = PropertyDetails(details).type();
10613 return Smi::FromInt(static_cast<int>(type));
10614}
10615
10616
10617// Return the property attribute calculated from the property details.
10618// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010619RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010620 ASSERT(args.length() == 1);
10621 CONVERT_CHECKED(Smi, details, args[0]);
10622 PropertyAttributes attributes = PropertyDetails(details).attributes();
10623 return Smi::FromInt(static_cast<int>(attributes));
10624}
10625
10626
10627// Return the property insertion index calculated from the property details.
10628// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010629RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010630 ASSERT(args.length() == 1);
10631 CONVERT_CHECKED(Smi, details, args[0]);
10632 int index = PropertyDetails(details).index();
10633 return Smi::FromInt(index);
10634}
10635
10636
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010637// Return property value from named interceptor.
10638// args[0]: object
10639// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010640RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010641 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010642 ASSERT(args.length() == 2);
10643 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10644 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10645 CONVERT_ARG_CHECKED(String, name, 1);
10646
10647 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010648 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010649}
10650
10651
10652// Return element value from indexed interceptor.
10653// args[0]: object
10654// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010655RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010656 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010657 ASSERT(args.length() == 2);
10658 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10659 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10660 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10661
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010662 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010663}
10664
10665
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010666RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010667 ASSERT(args.length() >= 1);
10668 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010669 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010670 if (isolate->debug()->break_id() == 0 ||
10671 break_id != isolate->debug()->break_id()) {
10672 return isolate->Throw(
10673 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010674 }
10675
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010676 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010677}
10678
10679
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010680RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010681 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010682 ASSERT(args.length() == 1);
10683
10684 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010685 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010686 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10687 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010688 if (!maybe_result->ToObject(&result)) return maybe_result;
10689 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690
10691 // Count all frames which are relevant to debugging stack trace.
10692 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010693 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010694 if (id == StackFrame::NO_ID) {
10695 // If there is no JavaScript stack frame count is 0.
10696 return Smi::FromInt(0);
10697 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010698
10699 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10700 n += it.frame()->GetInlineCount();
10701 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010702 return Smi::FromInt(n);
10703}
10704
10705
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010706class FrameInspector {
10707 public:
10708 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010709 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010710 Isolate* isolate)
10711 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10712 // Calculate the deoptimized frame.
10713 if (frame->is_optimized()) {
10714 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010715 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010716 }
10717 has_adapted_arguments_ = frame_->has_adapted_arguments();
10718 is_optimized_ = frame_->is_optimized();
10719 }
10720
10721 ~FrameInspector() {
10722 // Get rid of the calculated deoptimized frame if any.
10723 if (deoptimized_frame_ != NULL) {
10724 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10725 isolate_);
10726 }
10727 }
10728
10729 int GetParametersCount() {
10730 return is_optimized_
10731 ? deoptimized_frame_->parameters_count()
10732 : frame_->ComputeParametersCount();
10733 }
10734 int expression_count() { return deoptimized_frame_->expression_count(); }
10735 Object* GetFunction() {
10736 return is_optimized_
10737 ? deoptimized_frame_->GetFunction()
10738 : frame_->function();
10739 }
10740 Object* GetParameter(int index) {
10741 return is_optimized_
10742 ? deoptimized_frame_->GetParameter(index)
10743 : frame_->GetParameter(index);
10744 }
10745 Object* GetExpression(int index) {
10746 return is_optimized_
10747 ? deoptimized_frame_->GetExpression(index)
10748 : frame_->GetExpression(index);
10749 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010750 int GetSourcePosition() {
10751 return is_optimized_
10752 ? deoptimized_frame_->GetSourcePosition()
10753 : frame_->LookupCode()->SourcePosition(frame_->pc());
10754 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010755
10756 // To inspect all the provided arguments the frame might need to be
10757 // replaced with the arguments frame.
10758 void SetArgumentsFrame(JavaScriptFrame* frame) {
10759 ASSERT(has_adapted_arguments_);
10760 frame_ = frame;
10761 is_optimized_ = frame_->is_optimized();
10762 ASSERT(!is_optimized_);
10763 }
10764
10765 private:
10766 JavaScriptFrame* frame_;
10767 DeoptimizedFrameInfo* deoptimized_frame_;
10768 Isolate* isolate_;
10769 bool is_optimized_;
10770 bool has_adapted_arguments_;
10771
10772 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10773};
10774
10775
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776static const int kFrameDetailsFrameIdIndex = 0;
10777static const int kFrameDetailsReceiverIndex = 1;
10778static const int kFrameDetailsFunctionIndex = 2;
10779static const int kFrameDetailsArgumentCountIndex = 3;
10780static const int kFrameDetailsLocalCountIndex = 4;
10781static const int kFrameDetailsSourcePositionIndex = 5;
10782static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010783static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010784static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010785static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010786
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010787
10788static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10789 JavaScriptFrame* frame) {
10790 SaveContext* save = isolate->save_context();
10791 while (save != NULL && !save->IsBelowFrame(frame)) {
10792 save = save->prev();
10793 }
10794 ASSERT(save != NULL);
10795 return save;
10796}
10797
10798
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010799// Return an array with frame details
10800// args[0]: number: break id
10801// args[1]: number: frame index
10802//
10803// The array returned contains the following information:
10804// 0: Frame id
10805// 1: Receiver
10806// 2: Function
10807// 3: Argument count
10808// 4: Local count
10809// 5: Source position
10810// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010811// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010812// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010813// Arguments name, value
10814// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010815// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010816RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010817 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010818 ASSERT(args.length() == 2);
10819
10820 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010821 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010822 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10823 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010824 if (!maybe_check->ToObject(&check)) return maybe_check;
10825 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010826 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010827 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010828
10829 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010830 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010831 if (id == StackFrame::NO_ID) {
10832 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010833 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010834 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010835
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010836 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010837 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010838 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010839 if (index < count + it.frame()->GetInlineCount()) break;
10840 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010841 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010842 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010843
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010844 bool is_optimized = it.frame()->is_optimized();
10845
10846 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10847 if (is_optimized) {
10848 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010849 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010850 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010851 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010852
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010853 // Traverse the saved contexts chain to find the active context for the
10854 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010855 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010856
10857 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010858 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010859
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010860 // Find source position in unoptimized code.
10861 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010862
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010863 // Check for constructor frame. Inlined frames cannot be construct calls.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010864 bool inlined_frame = is_optimized && inlined_jsframe_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010865 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010866
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010867 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010868 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010869 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010870 Handle<ScopeInfo> scope_info(shared->scope_info());
10871 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010872
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873 // Get the locals names and values into a temporary array.
10874 //
10875 // TODO(1240907): Hide compiler-introduced stack variables
10876 // (e.g. .result)? For users of the debugger, they will probably be
10877 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010878 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010879 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010880
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010881 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010882 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010883 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010884 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010885 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010886 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010887 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010888 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010889 // Get the context containing declarations.
10890 Handle<Context> context(
10891 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010892 for (; i < scope_info->LocalCount(); ++i) {
10893 Handle<String> name(scope_info->LocalName(i));
10894 VariableMode mode;
10895 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010896 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010897 locals->set(i * 2 + 1, context->get(
10898 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010899 }
10900 }
10901
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010902 // Check whether this frame is positioned at return. If not top
10903 // frame or if the frame is optimized it cannot be at a return.
10904 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010905 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010906 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010907 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010908
10909 // If positioned just before return find the value to be returned and add it
10910 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010911 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010912 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010913 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010914 Address internal_frame_sp = NULL;
10915 while (!it2.done()) {
10916 if (it2.frame()->is_internal()) {
10917 internal_frame_sp = it2.frame()->sp();
10918 } else {
10919 if (it2.frame()->is_java_script()) {
10920 if (it2.frame()->id() == it.frame()->id()) {
10921 // The internal frame just before the JavaScript frame contains the
10922 // value to return on top. A debug break at return will create an
10923 // internal frame to store the return value (eax/rax/r0) before
10924 // entering the debug break exit frame.
10925 if (internal_frame_sp != NULL) {
10926 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010927 Handle<Object>(Memory::Object_at(internal_frame_sp),
10928 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010929 break;
10930 }
10931 }
10932 }
10933
10934 // Indicate that the previous frame was not an internal frame.
10935 internal_frame_sp = NULL;
10936 }
10937 it2.Advance();
10938 }
10939 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010940
10941 // Now advance to the arguments adapter frame (if any). It contains all
10942 // the provided parameters whereas the function frame always have the number
10943 // of arguments matching the functions parameters. The rest of the
10944 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010945 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010946 it.AdvanceToArgumentsFrame();
10947 frame_inspector.SetArgumentsFrame(it.frame());
10948 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010949
10950 // Find the number of arguments to fill. At least fill the number of
10951 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010952 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010953 if (argument_count < frame_inspector.GetParametersCount()) {
10954 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010955 }
10956
10957 // Calculate the size of the result.
10958 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010959 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010960 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010961 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010962
10963 // Add the frame id.
10964 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10965
10966 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010967 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968
10969 // Add the arguments count.
10970 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10971
10972 // Add the locals count
10973 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010974 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010975
10976 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010977 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010978 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10979 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010980 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010981 }
10982
10983 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010984 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010985
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010986 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010987 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010988
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010989 // Add flags to indicate information on whether this frame is
10990 // bit 0: invoked in the debugger context.
10991 // bit 1: optimized frame.
10992 // bit 2: inlined in optimized frame
10993 int flags = 0;
10994 if (*save->context() == *isolate->debug()->debug_context()) {
10995 flags |= 1 << 0;
10996 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010997 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010998 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010999 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011000 }
11001 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011002
11003 // Fill the dynamic part.
11004 int details_index = kFrameDetailsFirstDynamicIndex;
11005
11006 // Add arguments name and value.
11007 for (int i = 0; i < argument_count; i++) {
11008 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011009 if (i < scope_info->ParameterCount()) {
11010 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011011 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011012 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011013 }
11014
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011015 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011016 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011017 // Get the value from the stack.
11018 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011019 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011020 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011021 }
11022 }
11023
11024 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011025 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011026 details->set(details_index++, locals->get(i));
11027 }
11028
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011029 // Add the value being returned.
11030 if (at_return) {
11031 details->set(details_index++, *return_value);
11032 }
11033
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011034 // Add the receiver (same as in function frame).
11035 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11036 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011037 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011038 if (!receiver->IsJSObject() &&
11039 shared->is_classic_mode() &&
11040 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011041 // If the receiver is not a JSObject and the function is not a
11042 // builtin or strict-mode we have hit an optimization where a
11043 // value object is not converted into a wrapped JS objects. To
11044 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011045 // by creating correct wrapper object based on the calling frame's
11046 // global context.
11047 it.Advance();
11048 Handle<Context> calling_frames_global_context(
11049 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011050 receiver =
11051 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011052 }
11053 details->set(kFrameDetailsReceiverIndex, *receiver);
11054
11055 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011056 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011057}
11058
11059
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011060// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011061static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011062 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011063 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011064 Handle<Context> context,
11065 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011066 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011067 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11068 VariableMode mode;
11069 InitializationFlag init_flag;
11070 int context_index = scope_info->ContextSlotIndex(
11071 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011072
whesse@chromium.org7b260152011-06-20 15:33:18 +000011073 RETURN_IF_EMPTY_HANDLE_VALUE(
11074 isolate,
11075 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011076 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011077 Handle<Object>(context->get(context_index), isolate),
11078 NONE,
11079 kNonStrictMode),
11080 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011081 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011082
11083 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011084}
11085
11086
11087// Create a plain JSObject which materializes the local scope for the specified
11088// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011089static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011090 Isolate* isolate,
11091 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011092 FrameInspector* frame_inspector) {
11093 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011094 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011095 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011096
11097 // Allocate and initialize a JSObject with all the arguments, stack locals
11098 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011099 Handle<JSObject> local_scope =
11100 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011101
11102 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011103 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011104 Handle<Object> value(
11105 i < frame_inspector->GetParametersCount() ?
11106 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
11107
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011108 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011109 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011110 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011111 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011112 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011113 NONE,
11114 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011115 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011116 }
11117
11118 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011119 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011120 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011121 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011122 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011123 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011124 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011125 NONE,
11126 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011127 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011128 }
11129
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011130 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011131 // Third fill all context locals.
11132 Handle<Context> frame_context(Context::cast(frame->context()));
11133 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011134 if (!CopyContextLocalsToScopeObject(
11135 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011136 return Handle<JSObject>();
11137 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011138
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011139 // Finally copy any properties from the function context extension.
11140 // These will be variables introduced by eval.
11141 if (function_context->closure() == *function) {
11142 if (function_context->has_extension() &&
11143 !function_context->IsGlobalContext()) {
11144 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011145 bool threw = false;
11146 Handle<FixedArray> keys =
11147 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11148 if (threw) return Handle<JSObject>();
11149
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011150 for (int i = 0; i < keys->length(); i++) {
11151 // Names of variables introduced by eval are strings.
11152 ASSERT(keys->get(i)->IsString());
11153 Handle<String> key(String::cast(keys->get(i)));
11154 RETURN_IF_EMPTY_HANDLE_VALUE(
11155 isolate,
11156 SetProperty(local_scope,
11157 key,
11158 GetProperty(ext, key),
11159 NONE,
11160 kNonStrictMode),
11161 Handle<JSObject>());
11162 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011163 }
11164 }
11165 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011166
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011167 return local_scope;
11168}
11169
11170
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011171static Handle<JSObject> MaterializeLocalScope(
11172 Isolate* isolate,
11173 JavaScriptFrame* frame,
11174 int inlined_jsframe_index) {
11175 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11176 return MaterializeLocalScopeWithFrameInspector(isolate,
11177 frame,
11178 &frame_inspector);
11179}
11180
11181
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011182// Create a plain JSObject which materializes the closure content for the
11183// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011184static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11185 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011186 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011187
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011188 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011189 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011190
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011191 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011192 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011193 Handle<JSObject> closure_scope =
11194 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011195
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011196 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011197 if (!CopyContextLocalsToScopeObject(
11198 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011199 return Handle<JSObject>();
11200 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011201
11202 // Finally copy any properties from the function context extension. This will
11203 // be variables introduced by eval.
11204 if (context->has_extension()) {
11205 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011206 bool threw = false;
11207 Handle<FixedArray> keys =
11208 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11209 if (threw) return Handle<JSObject>();
11210
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011211 for (int i = 0; i < keys->length(); i++) {
11212 // Names of variables introduced by eval are strings.
11213 ASSERT(keys->get(i)->IsString());
11214 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011215 RETURN_IF_EMPTY_HANDLE_VALUE(
11216 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011217 SetProperty(closure_scope,
11218 key,
11219 GetProperty(ext, key),
11220 NONE,
11221 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011222 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011223 }
11224 }
11225
11226 return closure_scope;
11227}
11228
11229
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011230// Create a plain JSObject which materializes the scope for the specified
11231// catch context.
11232static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11233 Handle<Context> context) {
11234 ASSERT(context->IsCatchContext());
11235 Handle<String> name(String::cast(context->extension()));
11236 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11237 Handle<JSObject> catch_scope =
11238 isolate->factory()->NewJSObject(isolate->object_function());
11239 RETURN_IF_EMPTY_HANDLE_VALUE(
11240 isolate,
11241 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11242 Handle<JSObject>());
11243 return catch_scope;
11244}
11245
11246
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011247// Create a plain JSObject which materializes the block scope for the specified
11248// block context.
11249static Handle<JSObject> MaterializeBlockScope(
11250 Isolate* isolate,
11251 Handle<Context> context) {
11252 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011253 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011254
11255 // Allocate and initialize a JSObject with all the arguments, stack locals
11256 // heap locals and extension properties of the debugged function.
11257 Handle<JSObject> block_scope =
11258 isolate->factory()->NewJSObject(isolate->object_function());
11259
11260 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011261 if (!CopyContextLocalsToScopeObject(
11262 isolate, scope_info, context, block_scope)) {
11263 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011264 }
11265
11266 return block_scope;
11267}
11268
11269
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011270// Iterate over the actual scopes visible from a stack frame. The iteration
11271// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011272// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011273// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011274class ScopeIterator {
11275 public:
11276 enum ScopeType {
11277 ScopeTypeGlobal = 0,
11278 ScopeTypeLocal,
11279 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011280 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011281 ScopeTypeCatch,
11282 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011283 };
11284
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011285 ScopeIterator(Isolate* isolate,
11286 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011287 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011288 : isolate_(isolate),
11289 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011290 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011291 function_(JSFunction::cast(frame->function())),
11292 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011293 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011294
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011295 // Catch the case when the debugger stops in an internal function.
11296 Handle<SharedFunctionInfo> shared_info(function_->shared());
11297 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11298 if (shared_info->script() == isolate->heap()->undefined_value()) {
11299 while (context_->closure() == *function_) {
11300 context_ = Handle<Context>(context_->previous(), isolate_);
11301 }
11302 return;
11303 }
11304
11305 // Get the debug info (create it if it does not exist).
11306 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11307 // Return if ensuring debug info failed.
11308 return;
11309 }
11310 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11311
11312 // Find the break point where execution has stopped.
11313 BreakLocationIterator break_location_iterator(debug_info,
11314 ALL_BREAK_LOCATIONS);
11315 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11316 if (break_location_iterator.IsExit()) {
11317 // We are within the return sequence. At the momemt it is not possible to
11318 // get a source position which is consistent with the current scope chain.
11319 // Thus all nested with, catch and block contexts are skipped and we only
11320 // provide the function scope.
11321 if (scope_info->HasContext()) {
11322 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11323 } else {
11324 while (context_->closure() == *function_) {
11325 context_ = Handle<Context>(context_->previous(), isolate_);
11326 }
11327 }
11328 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11329 } else {
11330 // Reparse the code and analyze the scopes.
11331 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11332 Handle<Script> script(Script::cast(shared_info->script()));
11333 Scope* scope = NULL;
11334
11335 // Check whether we are in global, eval or function code.
11336 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11337 if (scope_info->Type() != FUNCTION_SCOPE) {
11338 // Global or eval code.
11339 CompilationInfo info(script);
11340 if (scope_info->Type() == GLOBAL_SCOPE) {
11341 info.MarkAsGlobal();
11342 } else {
11343 ASSERT(scope_info->Type() == EVAL_SCOPE);
11344 info.MarkAsEval();
11345 info.SetCallingContext(Handle<Context>(function_->context()));
11346 }
11347 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11348 scope = info.function()->scope();
11349 }
11350 } else {
11351 // Function code
11352 CompilationInfo info(shared_info);
11353 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11354 scope = info.function()->scope();
11355 }
11356 }
11357
11358 // Retrieve the scope chain for the current position.
11359 if (scope != NULL) {
11360 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11361 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11362 } else {
11363 // A failed reparse indicates that the preparser has diverged from the
11364 // parser or that the preparse data given to the initial parse has been
11365 // faulty. We fail in debug mode but in release mode we only provide the
11366 // information we get from the context chain but nothing about
11367 // completely stack allocated scopes or stack allocated locals.
11368 UNREACHABLE();
11369 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011370 }
11371 }
11372
11373 // More scopes?
11374 bool Done() { return context_.is_null(); }
11375
11376 // Move to the next scope.
11377 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011378 ScopeType scope_type = Type();
11379 if (scope_type == ScopeTypeGlobal) {
11380 // The global scope is always the last in the chain.
11381 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011382 context_ = Handle<Context>();
11383 return;
11384 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011385 if (nested_scope_chain_.is_empty()) {
11386 context_ = Handle<Context>(context_->previous(), isolate_);
11387 } else {
11388 if (nested_scope_chain_.last()->HasContext()) {
11389 ASSERT(context_->previous() != NULL);
11390 context_ = Handle<Context>(context_->previous(), isolate_);
11391 }
11392 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011393 }
11394 }
11395
11396 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011397 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011398 if (!nested_scope_chain_.is_empty()) {
11399 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11400 switch (scope_info->Type()) {
11401 case FUNCTION_SCOPE:
11402 ASSERT(context_->IsFunctionContext() ||
11403 !scope_info->HasContext());
11404 return ScopeTypeLocal;
11405 case GLOBAL_SCOPE:
11406 ASSERT(context_->IsGlobalContext());
11407 return ScopeTypeGlobal;
11408 case WITH_SCOPE:
11409 ASSERT(context_->IsWithContext());
11410 return ScopeTypeWith;
11411 case CATCH_SCOPE:
11412 ASSERT(context_->IsCatchContext());
11413 return ScopeTypeCatch;
11414 case BLOCK_SCOPE:
11415 ASSERT(!scope_info->HasContext() ||
11416 context_->IsBlockContext());
11417 return ScopeTypeBlock;
11418 case EVAL_SCOPE:
11419 UNREACHABLE();
11420 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011421 }
11422 if (context_->IsGlobalContext()) {
11423 ASSERT(context_->global()->IsGlobalObject());
11424 return ScopeTypeGlobal;
11425 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011426 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011427 return ScopeTypeClosure;
11428 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011429 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011430 return ScopeTypeCatch;
11431 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011432 if (context_->IsBlockContext()) {
11433 return ScopeTypeBlock;
11434 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011435 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011436 return ScopeTypeWith;
11437 }
11438
11439 // Return the JavaScript object with the content of the current scope.
11440 Handle<JSObject> ScopeObject() {
11441 switch (Type()) {
11442 case ScopeIterator::ScopeTypeGlobal:
11443 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011444 case ScopeIterator::ScopeTypeLocal:
11445 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011446 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011447 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011448 case ScopeIterator::ScopeTypeWith:
11449 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011450 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11451 case ScopeIterator::ScopeTypeCatch:
11452 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011453 case ScopeIterator::ScopeTypeClosure:
11454 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011455 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011456 case ScopeIterator::ScopeTypeBlock:
11457 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011458 }
11459 UNREACHABLE();
11460 return Handle<JSObject>();
11461 }
11462
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011463 Handle<ScopeInfo> CurrentScopeInfo() {
11464 if (!nested_scope_chain_.is_empty()) {
11465 return nested_scope_chain_.last();
11466 } else if (context_->IsBlockContext()) {
11467 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11468 } else if (context_->IsFunctionContext()) {
11469 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11470 }
11471 return Handle<ScopeInfo>::null();
11472 }
11473
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011474 // Return the context for this scope. For the local context there might not
11475 // be an actual context.
11476 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011477 if (Type() == ScopeTypeGlobal ||
11478 nested_scope_chain_.is_empty()) {
11479 return context_;
11480 } else if (nested_scope_chain_.last()->HasContext()) {
11481 return context_;
11482 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011483 return Handle<Context>();
11484 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011485 }
11486
11487#ifdef DEBUG
11488 // Debug print of the content of the current scope.
11489 void DebugPrint() {
11490 switch (Type()) {
11491 case ScopeIterator::ScopeTypeGlobal:
11492 PrintF("Global:\n");
11493 CurrentContext()->Print();
11494 break;
11495
11496 case ScopeIterator::ScopeTypeLocal: {
11497 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011498 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011499 if (!CurrentContext().is_null()) {
11500 CurrentContext()->Print();
11501 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011502 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011503 if (extension->IsJSContextExtensionObject()) {
11504 extension->Print();
11505 }
11506 }
11507 }
11508 break;
11509 }
11510
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011511 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011512 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011513 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011514 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011515
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011516 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011517 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011518 CurrentContext()->extension()->Print();
11519 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011520 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011521
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011522 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011523 PrintF("Closure:\n");
11524 CurrentContext()->Print();
11525 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011526 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011527 if (extension->IsJSContextExtensionObject()) {
11528 extension->Print();
11529 }
11530 }
11531 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011532
11533 default:
11534 UNREACHABLE();
11535 }
11536 PrintF("\n");
11537 }
11538#endif
11539
11540 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011541 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011542 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011543 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011544 Handle<JSFunction> function_;
11545 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011546 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011547
11548 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11549};
11550
11551
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011552RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011553 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011554 ASSERT(args.length() == 2);
11555
11556 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011557 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011558 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11559 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011560 if (!maybe_check->ToObject(&check)) return maybe_check;
11561 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011562 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11563
11564 // Get the frame where the debugging is performed.
11565 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011566 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011567 JavaScriptFrame* frame = it.frame();
11568
11569 // Count the visible scopes.
11570 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011571 for (ScopeIterator it(isolate, frame, 0);
11572 !it.Done();
11573 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011574 n++;
11575 }
11576
11577 return Smi::FromInt(n);
11578}
11579
11580
11581static const int kScopeDetailsTypeIndex = 0;
11582static const int kScopeDetailsObjectIndex = 1;
11583static const int kScopeDetailsSize = 2;
11584
11585// Return an array with scope details
11586// args[0]: number: break id
11587// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011588// args[2]: number: inlined frame index
11589// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011590//
11591// The array returned contains the following information:
11592// 0: Scope type
11593// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011594RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011595 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011596 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011597
11598 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011599 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011600 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11601 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011602 if (!maybe_check->ToObject(&check)) return maybe_check;
11603 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011604 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011605 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011606 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011607
11608 // Get the frame where the debugging is performed.
11609 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011610 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011611 JavaScriptFrame* frame = frame_it.frame();
11612
11613 // Find the requested scope.
11614 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011615 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011616 for (; !it.Done() && n < index; it.Next()) {
11617 n++;
11618 }
11619 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011620 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011621 }
11622
11623 // Calculate the size of the result.
11624 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011626
11627 // Fill in scope details.
11628 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011629 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011630 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011631 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011632
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011633 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011634}
11635
11636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011637RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011638 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011639 ASSERT(args.length() == 0);
11640
11641#ifdef DEBUG
11642 // Print the scopes for the top frame.
11643 StackFrameLocator locator;
11644 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011645 for (ScopeIterator it(isolate, frame, 0);
11646 !it.Done();
11647 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011648 it.DebugPrint();
11649 }
11650#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011651 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011652}
11653
11654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011655RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011656 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011657 ASSERT(args.length() == 1);
11658
11659 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011660 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011661 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11662 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011663 if (!maybe_result->ToObject(&result)) return maybe_result;
11664 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011665
11666 // Count all archived V8 threads.
11667 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011668 for (ThreadState* thread =
11669 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011670 thread != NULL;
11671 thread = thread->Next()) {
11672 n++;
11673 }
11674
11675 // Total number of threads is current thread and archived threads.
11676 return Smi::FromInt(n + 1);
11677}
11678
11679
11680static const int kThreadDetailsCurrentThreadIndex = 0;
11681static const int kThreadDetailsThreadIdIndex = 1;
11682static const int kThreadDetailsSize = 2;
11683
11684// Return an array with thread details
11685// args[0]: number: break id
11686// args[1]: number: thread index
11687//
11688// The array returned contains the following information:
11689// 0: Is current thread?
11690// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011691RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011692 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011693 ASSERT(args.length() == 2);
11694
11695 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011696 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011697 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11698 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011699 if (!maybe_check->ToObject(&check)) return maybe_check;
11700 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011701 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11702
11703 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011704 Handle<FixedArray> details =
11705 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011706
11707 // Thread index 0 is current thread.
11708 if (index == 0) {
11709 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011710 details->set(kThreadDetailsCurrentThreadIndex,
11711 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011712 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011713 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011714 } else {
11715 // Find the thread with the requested index.
11716 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011717 ThreadState* thread =
11718 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011719 while (index != n && thread != NULL) {
11720 thread = thread->Next();
11721 n++;
11722 }
11723 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011724 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011725 }
11726
11727 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011728 details->set(kThreadDetailsCurrentThreadIndex,
11729 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011730 details->set(kThreadDetailsThreadIdIndex,
11731 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011732 }
11733
11734 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011735 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011736}
11737
11738
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011739// Sets the disable break state
11740// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011741RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011742 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011743 ASSERT(args.length() == 1);
11744 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011745 isolate->debug()->set_disable_break(disable_break);
11746 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011747}
11748
11749
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011750RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011751 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011752 ASSERT(args.length() == 1);
11753
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011754 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11755 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011756 // Find the number of break points
11757 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011758 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011759 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011760 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011761 Handle<FixedArray>::cast(break_locations));
11762}
11763
11764
11765// Set a break point in a function
11766// args[0]: function
11767// args[1]: number: break source position (within the function source)
11768// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011769RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011770 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011771 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011772 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11773 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11775 RUNTIME_ASSERT(source_position >= 0);
11776 Handle<Object> break_point_object_arg = args.at<Object>(2);
11777
11778 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011779 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11780 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011781
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011782 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011783}
11784
11785
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011786Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11787 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011788 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011789 // Iterate the heap looking for SharedFunctionInfo generated from the
11790 // script. The inner most SharedFunctionInfo containing the source position
11791 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011792 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011793 // which is found is not compiled it is compiled and the heap is iterated
11794 // again as the compilation might create inner functions from the newly
11795 // compiled function and the actual requested break point might be in one of
11796 // these functions.
11797 bool done = false;
11798 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011799 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011800 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011801 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011802 { // Extra scope for iterator and no-allocation.
11803 isolate->heap()->EnsureHeapIsIterable();
11804 AssertNoAllocation no_alloc_during_heap_iteration;
11805 HeapIterator iterator;
11806 for (HeapObject* obj = iterator.next();
11807 obj != NULL; obj = iterator.next()) {
11808 if (obj->IsSharedFunctionInfo()) {
11809 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11810 if (shared->script() == *script) {
11811 // If the SharedFunctionInfo found has the requested script data and
11812 // contains the source position it is a candidate.
11813 int start_position = shared->function_token_position();
11814 if (start_position == RelocInfo::kNoPosition) {
11815 start_position = shared->start_position();
11816 }
11817 if (start_position <= position &&
11818 position <= shared->end_position()) {
11819 // If there is no candidate or this function is within the current
11820 // candidate this is the new candidate.
11821 if (target.is_null()) {
11822 target_start_position = start_position;
11823 target = shared;
11824 } else {
11825 if (target_start_position == start_position &&
11826 shared->end_position() == target->end_position()) {
11827 // If a top-level function contain only one function
11828 // declartion the source for the top-level and the
11829 // function is the same. In that case prefer the non
11830 // top-level function.
11831 if (!shared->is_toplevel()) {
11832 target_start_position = start_position;
11833 target = shared;
11834 }
11835 } else if (target_start_position <= start_position &&
11836 shared->end_position() <= target->end_position()) {
11837 // This containment check includes equality as a function
11838 // inside a top-level function can share either start or end
11839 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011840 target_start_position = start_position;
11841 target = shared;
11842 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011843 }
11844 }
11845 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011846 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011847 } // End for loop.
11848 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011849
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011850 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011851 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011852 }
11853
11854 // If the candidate found is compiled we are done. NOTE: when lazy
11855 // compilation of inner functions is introduced some additional checking
11856 // needs to be done here to compile inner functions.
11857 done = target->is_compiled();
11858 if (!done) {
11859 // If the candidate is not compiled compile it to reveal any inner
11860 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011861 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011862 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011863 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011864
11865 return *target;
11866}
11867
11868
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011869// Changes the state of a break point in a script and returns source position
11870// where break point was set. NOTE: Regarding performance see the NOTE for
11871// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011872// args[0]: script to set break point in
11873// args[1]: number: break source position (within the script source)
11874// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011875RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011876 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011877 ASSERT(args.length() == 3);
11878 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11879 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11880 RUNTIME_ASSERT(source_position >= 0);
11881 Handle<Object> break_point_object_arg = args.at<Object>(2);
11882
11883 // Get the script from the script wrapper.
11884 RUNTIME_ASSERT(wrapper->value()->IsScript());
11885 Handle<Script> script(Script::cast(wrapper->value()));
11886
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011887 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011888 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011889 if (!result->IsUndefined()) {
11890 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11891 // Find position within function. The script position might be before the
11892 // source position of the first function.
11893 int position;
11894 if (shared->start_position() > source_position) {
11895 position = 0;
11896 } else {
11897 position = source_position - shared->start_position();
11898 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011899 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011900 position += shared->start_position();
11901 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011902 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011903 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011904}
11905
11906
11907// Clear a break point
11908// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011909RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011910 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011911 ASSERT(args.length() == 1);
11912 Handle<Object> break_point_object_arg = args.at<Object>(0);
11913
11914 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011915 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011917 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011918}
11919
11920
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011921// Change the state of break on exceptions.
11922// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11923// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011924RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011925 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011926 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011927 RUNTIME_ASSERT(args[0]->IsNumber());
11928 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011929
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011930 // If the number doesn't match an enum value, the ChangeBreakOnException
11931 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011932 ExceptionBreakType type =
11933 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011934 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011935 isolate->debug()->ChangeBreakOnException(type, enable);
11936 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011937}
11938
11939
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011940// Returns the state of break on exceptions
11941// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011942RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011943 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011944 ASSERT(args.length() == 1);
11945 RUNTIME_ASSERT(args[0]->IsNumber());
11946
11947 ExceptionBreakType type =
11948 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011949 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011950 return Smi::FromInt(result);
11951}
11952
11953
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011954// Prepare for stepping
11955// args[0]: break id for checking execution state
11956// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011957// args[2]: number of times to perform the step, for step out it is the number
11958// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011959RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011960 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011961 ASSERT(args.length() == 3);
11962 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011963 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011964 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11965 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011966 if (!maybe_check->ToObject(&check)) return maybe_check;
11967 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011968 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011969 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011970 }
11971
11972 // Get the step action and check validity.
11973 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11974 if (step_action != StepIn &&
11975 step_action != StepNext &&
11976 step_action != StepOut &&
11977 step_action != StepInMin &&
11978 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011979 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011980 }
11981
11982 // Get the number of steps.
11983 int step_count = NumberToInt32(args[2]);
11984 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011985 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011986 }
11987
ager@chromium.orga1645e22009-09-09 19:27:10 +000011988 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011989 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011990
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011991 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011992 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11993 step_count);
11994 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011995}
11996
11997
11998// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011999RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012000 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012001 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012002 isolate->debug()->ClearStepping();
12003 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012004}
12005
12006
12007// Creates a copy of the with context chain. The copy of the context chain is
12008// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012009static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
12010 Handle<JSFunction> function,
12011 Handle<Context> base,
12012 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012013 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012014 HandleScope scope(isolate);
12015 List<Handle<ScopeInfo> > scope_chain;
12016 List<Handle<Context> > context_chain;
12017
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012018 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012019 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
12020 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
12021 ASSERT(!it.Done());
12022 scope_chain.Add(it.CurrentScopeInfo());
12023 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012024 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012025
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012026 // At the end of the chain. Return the base context to link to.
12027 Handle<Context> context = base;
12028
12029 // Iteratively copy and or materialize the nested contexts.
12030 while (!scope_chain.is_empty()) {
12031 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
12032 Handle<Context> current = context_chain.RemoveLast();
12033 ASSERT(!(scope_info->HasContext() & current.is_null()));
12034
12035 if (scope_info->Type() == CATCH_SCOPE) {
12036 Handle<String> name(String::cast(current->extension()));
12037 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
12038 context =
12039 isolate->factory()->NewCatchContext(function,
12040 context,
12041 name,
12042 thrown_object);
12043 } else if (scope_info->Type() == BLOCK_SCOPE) {
12044 // Materialize the contents of the block scope into a JSObject.
12045 Handle<JSObject> block_scope_object =
12046 MaterializeBlockScope(isolate, current);
12047 if (block_scope_object.is_null()) {
12048 return Handle<Context>::null();
12049 }
12050 // Allocate a new function context for the debug evaluation and set the
12051 // extension object.
12052 Handle<Context> new_context =
12053 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12054 function);
12055 new_context->set_extension(*block_scope_object);
12056 new_context->set_previous(*context);
12057 context = new_context;
12058 } else {
12059 ASSERT(scope_info->Type() == WITH_SCOPE);
12060 ASSERT(current->IsWithContext());
12061 Handle<JSObject> extension(JSObject::cast(current->extension()));
12062 context =
12063 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000012064 }
erikcorry0ad885c2011-11-21 13:51:57 +000012065 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012066
12067 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012068}
12069
12070
12071// Helper function to find or create the arguments object for
12072// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012073static Handle<Object> GetArgumentsObject(Isolate* isolate,
12074 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012075 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012076 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012077 Handle<Context> function_context) {
12078 // Try to find the value of 'arguments' to pass as parameter. If it is not
12079 // found (that is the debugged function does not reference 'arguments' and
12080 // does not support eval) then create an 'arguments' object.
12081 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012082 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012083 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012084 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012085 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012086 }
12087 }
12088
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012089 if (scope_info->HasHeapAllocatedLocals()) {
12090 VariableMode mode;
12091 InitializationFlag init_flag;
12092 index = scope_info->ContextSlotIndex(
12093 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012094 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012095 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012096 }
12097 }
12098
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012099 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
12100 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012101 Handle<JSObject> arguments =
12102 isolate->factory()->NewArgumentsObject(function, length);
12103 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012104
12105 AssertNoAllocation no_gc;
12106 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012107 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012108 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012109 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012110 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012111 return arguments;
12112}
12113
12114
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012115static const char kSourceStr[] =
12116 "(function(arguments,__source__){return eval(__source__);})";
12117
12118
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012119// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012120// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012121// extension part has all the parameters and locals of the function on the
12122// stack frame. A function which calls eval with the code to evaluate is then
12123// compiled in this context and called in this context. As this context
12124// replaces the context of the function on the stack frame a new (empty)
12125// function is created as well to be used as the closure for the context.
12126// This function and the context acts as replacements for the function on the
12127// stack frame presenting the same view of the values of parameters and
12128// local variables as if the piece of JavaScript was evaluated at the point
12129// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012130RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012131 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012132
12133 // Check the execution state and decode arguments frame and source to be
12134 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012135 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012136 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012137 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12138 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012139 if (!maybe_check_result->ToObject(&check_result)) {
12140 return maybe_check_result;
12141 }
12142 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012143 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012144 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012145 CONVERT_ARG_CHECKED(String, source, 3);
12146 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12147 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012148
12149 // Handle the processing of break.
12150 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012151
12152 // Get the frame where the debugging is performed.
12153 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012154 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012155 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012156 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12157 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012158 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012159
12160 // Traverse the saved contexts chain to find the active context for the
12161 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012162 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12163
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012164 SaveContext savex(isolate);
12165 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012166
12167 // Create the (empty) function replacing the function on the stack frame for
12168 // the purpose of evaluating in the context created below. It is important
12169 // that this function does not describe any parameters and local variables
12170 // in the context. If it does then this will cause problems with the lookup
12171 // in Context::Lookup, where context slots for parameters and local variables
12172 // are looked at before the extension object.
12173 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012174 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12175 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012176 go_between->set_context(function->context());
12177#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012178 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12179 ASSERT(go_between_scope_info->ParameterCount() == 0);
12180 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012181#endif
12182
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012183 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012184 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
12185 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012186 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012187
12188 // Allocate a new context for the debug evaluation and set the extension
12189 // object build.
12190 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012191 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12192 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012193 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012194 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012195 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012196 Handle<Context> function_context;
12197 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012198 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012199 function_context = Handle<Context>(frame_context->declaration_context());
12200 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012201 context = CopyNestedScopeContextChain(isolate,
12202 go_between,
12203 context,
12204 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012205 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012206
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012207 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012208 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012209 context =
12210 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012211 }
12212
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012213 // Wrap the evaluation statement in a new function compiled in the newly
12214 // created context. The function has one parameter which has to be called
12215 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012216 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012217 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012218
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012219 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012220 isolate->factory()->NewStringFromAscii(
12221 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012222
12223 // Currently, the eval code will be executed in non-strict mode,
12224 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012225 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012226 Compiler::CompileEval(function_source,
12227 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012228 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012229 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012230 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012231 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012232 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012233 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012234
12235 // Invoke the result of the compilation to get the evaluation function.
12236 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012237 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012238 Handle<Object> evaluation_function =
12239 Execution::Call(compiled_function, receiver, 0, NULL,
12240 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012241 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012242
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012243 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012244 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012245 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012246 scope_info,
12247 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012248
12249 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012250 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012251 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012252 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12253 receiver,
12254 ARRAY_SIZE(argv),
12255 argv,
12256 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012257 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012258
12259 // Skip the global proxy as it has no properties and always delegates to the
12260 // real global object.
12261 if (result->IsJSGlobalProxy()) {
12262 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12263 }
12264
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012265 return *result;
12266}
12267
12268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012269RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012270 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012271
12272 // Check the execution state and decode arguments frame and source to be
12273 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012274 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012275 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012276 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12277 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012278 if (!maybe_check_result->ToObject(&check_result)) {
12279 return maybe_check_result;
12280 }
12281 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012282 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012283 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012284 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012285
12286 // Handle the processing of break.
12287 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012288
12289 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012290 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012291 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012292 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012293 top = top->prev();
12294 }
12295 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012296 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012297 }
12298
12299 // Get the global context now set to the top context from before the
12300 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012301 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012302
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012303 bool is_global = true;
12304
12305 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012306 // Create a new with context with the additional context information between
12307 // the context of the debugged function and the eval code to be executed.
12308 context = isolate->factory()->NewWithContext(
12309 Handle<JSFunction>(context->closure()),
12310 context,
12311 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012312 is_global = false;
12313 }
12314
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012315 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012316 // Currently, the eval code will be executed in non-strict mode,
12317 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012318 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012319 Compiler::CompileEval(source,
12320 context,
12321 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012322 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012323 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012324 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012325 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012326 Handle<JSFunction>(
12327 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12328 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012329
12330 // Invoke the result of the compilation to get the evaluation function.
12331 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012332 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012333 Handle<Object> result =
12334 Execution::Call(compiled_function, receiver, 0, NULL,
12335 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012336 // Clear the oneshot breakpoints so that the debugger does not step further.
12337 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012338 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012339 return *result;
12340}
12341
12342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012343RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012344 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012345 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012346
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012347 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012348 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012349
12350 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012351 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012352 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12353 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12354 // because using
12355 // instances->set(i, *GetScriptWrapper(script))
12356 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012357 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012358 Handle<JSValue> wrapper = GetScriptWrapper(script);
12359 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012360 }
12361
12362 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012363 Handle<JSObject> result =
12364 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012365 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012366 return *result;
12367}
12368
12369
12370// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012371static int DebugReferencedBy(HeapIterator* iterator,
12372 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012373 Object* instance_filter, int max_references,
12374 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012375 JSFunction* arguments_function) {
12376 NoHandleAllocation ha;
12377 AssertNoAllocation no_alloc;
12378
12379 // Iterate the heap.
12380 int count = 0;
12381 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012382 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012383 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012384 (max_references == 0 || count < max_references)) {
12385 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012386 if (heap_obj->IsJSObject()) {
12387 // Skip context extension objects and argument arrays as these are
12388 // checked in the context of functions using them.
12389 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012390 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012391 obj->map()->constructor() == arguments_function) {
12392 continue;
12393 }
12394
12395 // Check if the JS object has a reference to the object looked for.
12396 if (obj->ReferencesObject(target)) {
12397 // Check instance filter if supplied. This is normally used to avoid
12398 // references from mirror objects (see Runtime_IsInPrototypeChain).
12399 if (!instance_filter->IsUndefined()) {
12400 Object* V = obj;
12401 while (true) {
12402 Object* prototype = V->GetPrototype();
12403 if (prototype->IsNull()) {
12404 break;
12405 }
12406 if (instance_filter == prototype) {
12407 obj = NULL; // Don't add this object.
12408 break;
12409 }
12410 V = prototype;
12411 }
12412 }
12413
12414 if (obj != NULL) {
12415 // Valid reference found add to instance array if supplied an update
12416 // count.
12417 if (instances != NULL && count < instances_size) {
12418 instances->set(count, obj);
12419 }
12420 last = obj;
12421 count++;
12422 }
12423 }
12424 }
12425 }
12426
12427 // Check for circular reference only. This can happen when the object is only
12428 // referenced from mirrors and has a circular reference in which case the
12429 // object is not really alive and would have been garbage collected if not
12430 // referenced from the mirror.
12431 if (count == 1 && last == target) {
12432 count = 0;
12433 }
12434
12435 // Return the number of referencing objects found.
12436 return count;
12437}
12438
12439
12440// Scan the heap for objects with direct references to an object
12441// args[0]: the object to find references to
12442// args[1]: constructor function for instances to exclude (Mirror)
12443// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012444RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012445 ASSERT(args.length() == 3);
12446
12447 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012448 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12449 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012450 // The heap iterator reserves the right to do a GC to make the heap iterable.
12451 // Due to the GC above we know it won't need to do that, but it seems cleaner
12452 // to get the heap iterator constructed before we start having unprotected
12453 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012454
12455 // Check parameters.
12456 CONVERT_CHECKED(JSObject, target, args[0]);
12457 Object* instance_filter = args[1];
12458 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12459 instance_filter->IsJSObject());
12460 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12461 RUNTIME_ASSERT(max_references >= 0);
12462
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012463
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012464 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012465 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012466 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012467 JSFunction* arguments_function =
12468 JSFunction::cast(arguments_boilerplate->map()->constructor());
12469
12470 // Get the number of referencing objects.
12471 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012472 HeapIterator heap_iterator;
12473 count = DebugReferencedBy(&heap_iterator,
12474 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012475 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012476
12477 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012478 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012479 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012480 if (!maybe_object->ToObject(&object)) return maybe_object;
12481 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012482 FixedArray* instances = FixedArray::cast(object);
12483
12484 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012485 // AllocateFixedArray above does not make the heap non-iterable.
12486 ASSERT(HEAP->IsHeapIterable());
12487 HeapIterator heap_iterator2;
12488 count = DebugReferencedBy(&heap_iterator2,
12489 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012490 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012491
12492 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012493 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012494 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012495 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012496 if (!maybe_result->ToObject(&result)) return maybe_result;
12497 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012498}
12499
12500
12501// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012502static int DebugConstructedBy(HeapIterator* iterator,
12503 JSFunction* constructor,
12504 int max_references,
12505 FixedArray* instances,
12506 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012507 AssertNoAllocation no_alloc;
12508
12509 // Iterate the heap.
12510 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012511 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012512 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012513 (max_references == 0 || count < max_references)) {
12514 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012515 if (heap_obj->IsJSObject()) {
12516 JSObject* obj = JSObject::cast(heap_obj);
12517 if (obj->map()->constructor() == constructor) {
12518 // Valid reference found add to instance array if supplied an update
12519 // count.
12520 if (instances != NULL && count < instances_size) {
12521 instances->set(count, obj);
12522 }
12523 count++;
12524 }
12525 }
12526 }
12527
12528 // Return the number of referencing objects found.
12529 return count;
12530}
12531
12532
12533// Scan the heap for objects constructed by a specific function.
12534// args[0]: the constructor to find instances of
12535// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012536RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012537 ASSERT(args.length() == 2);
12538
12539 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012540 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12541 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012542
12543 // Check parameters.
12544 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12545 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12546 RUNTIME_ASSERT(max_references >= 0);
12547
12548 // Get the number of referencing objects.
12549 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012550 HeapIterator heap_iterator;
12551 count = DebugConstructedBy(&heap_iterator,
12552 constructor,
12553 max_references,
12554 NULL,
12555 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012556
12557 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012558 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012559 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012560 if (!maybe_object->ToObject(&object)) return maybe_object;
12561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012562 FixedArray* instances = FixedArray::cast(object);
12563
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012564 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012565 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012566 HeapIterator heap_iterator2;
12567 count = DebugConstructedBy(&heap_iterator2,
12568 constructor,
12569 max_references,
12570 instances,
12571 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012572
12573 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012574 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012575 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12576 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012577 if (!maybe_result->ToObject(&result)) return maybe_result;
12578 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012579 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012580}
12581
12582
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012583// Find the effective prototype object as returned by __proto__.
12584// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012585RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012586 ASSERT(args.length() == 1);
12587
12588 CONVERT_CHECKED(JSObject, obj, args[0]);
12589
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012590 // Use the __proto__ accessor.
12591 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012592}
12593
12594
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012595RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012596 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012597 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012598 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012599}
12600
12601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012602RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012603#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012604 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012605 ASSERT(args.length() == 1);
12606 // Get the function and make sure it is compiled.
12607 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012608 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012609 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012610 return Failure::Exception();
12611 }
12612 func->code()->PrintLn();
12613#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012614 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012615}
ager@chromium.org9085a012009-05-11 19:22:57 +000012616
12617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012618RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012619#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012620 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012621 ASSERT(args.length() == 1);
12622 // Get the function and make sure it is compiled.
12623 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012624 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012625 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012626 return Failure::Exception();
12627 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012628 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012629#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012630 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012631}
12632
12633
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012634RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012635 NoHandleAllocation ha;
12636 ASSERT(args.length() == 1);
12637
12638 CONVERT_CHECKED(JSFunction, f, args[0]);
12639 return f->shared()->inferred_name();
12640}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012641
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012642
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012643static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12644 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012645 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012646 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012647 int counter = 0;
12648 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012649 for (HeapObject* obj = iterator->next();
12650 obj != NULL;
12651 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012652 ASSERT(obj != NULL);
12653 if (!obj->IsSharedFunctionInfo()) {
12654 continue;
12655 }
12656 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12657 if (shared->script() != script) {
12658 continue;
12659 }
12660 if (counter < buffer_size) {
12661 buffer->set(counter, shared);
12662 }
12663 counter++;
12664 }
12665 return counter;
12666}
12667
12668// For a script finds all SharedFunctionInfo's in the heap that points
12669// to this script. Returns JSArray of SharedFunctionInfo wrapped
12670// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012671RUNTIME_FUNCTION(MaybeObject*,
12672 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012673 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012674 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012675 CONVERT_CHECKED(JSValue, script_value, args[0]);
12676
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012677
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012678 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12679
12680 const int kBufferSize = 32;
12681
12682 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012683 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012684 int number;
12685 {
12686 isolate->heap()->EnsureHeapIsIterable();
12687 AssertNoAllocation no_allocations;
12688 HeapIterator heap_iterator;
12689 Script* scr = *script;
12690 FixedArray* arr = *array;
12691 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12692 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012693 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012694 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012695 isolate->heap()->EnsureHeapIsIterable();
12696 AssertNoAllocation no_allocations;
12697 HeapIterator heap_iterator;
12698 Script* scr = *script;
12699 FixedArray* arr = *array;
12700 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012701 }
12702
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012703 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012704 result->set_length(Smi::FromInt(number));
12705
12706 LiveEdit::WrapSharedFunctionInfos(result);
12707
12708 return *result;
12709}
12710
12711// For a script calculates compilation information about all its functions.
12712// The script source is explicitly specified by the second argument.
12713// The source of the actual script is not used, however it is important that
12714// all generated code keeps references to this particular instance of script.
12715// Returns a JSArray of compilation infos. The array is ordered so that
12716// each function with all its descendant is always stored in a continues range
12717// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012718RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012719 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012720 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012721 CONVERT_CHECKED(JSValue, script, args[0]);
12722 CONVERT_ARG_CHECKED(String, source, 1);
12723 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12724
12725 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012727 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012728 return Failure::Exception();
12729 }
12730
12731 return result;
12732}
12733
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012734// Changes the source of the script to a new_source.
12735// If old_script_name is provided (i.e. is a String), also creates a copy of
12736// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012737RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012738 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012739 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012740 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12741 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012742 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012743
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012744 CONVERT_CHECKED(Script, original_script_pointer,
12745 original_script_value->value());
12746 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012747
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012748 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12749 new_source,
12750 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012751
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012752 if (old_script->IsScript()) {
12753 Handle<Script> script_handle(Script::cast(old_script));
12754 return *(GetScriptWrapper(script_handle));
12755 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012756 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012757 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012758}
12759
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012760
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012761RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012762 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012763 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012764 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12765 return LiveEdit::FunctionSourceUpdated(shared_info);
12766}
12767
12768
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012769// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012770RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012771 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012772 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012773 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12774 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12775
ager@chromium.orgac091b72010-05-05 07:34:42 +000012776 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012777}
12778
12779// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012780RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012781 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012782 HandleScope scope(isolate);
12783 Handle<Object> function_object(args[0], isolate);
12784 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012785
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012786 if (function_object->IsJSValue()) {
12787 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12788 if (script_object->IsJSValue()) {
12789 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012790 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012791 }
12792
12793 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12794 } else {
12795 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12796 // and we check it in this function.
12797 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012798
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012799 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012800}
12801
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012802
12803// In a code of a parent function replaces original function as embedded object
12804// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012805RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012806 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012807 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012808
12809 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12810 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12811 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12812
12813 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12814 subst_wrapper);
12815
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012816 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012817}
12818
12819
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012820// Updates positions of a shared function info (first parameter) according
12821// to script source change. Text change is described in second parameter as
12822// array of groups of 3 numbers:
12823// (change_begin, change_end, change_end_new_position).
12824// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012825RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012826 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012827 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012828 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12829 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12830
ager@chromium.orgac091b72010-05-05 07:34:42 +000012831 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012832}
12833
12834
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012835// For array of SharedFunctionInfo's (each wrapped in JSValue)
12836// checks that none of them have activations on stacks (of any thread).
12837// Returns array of the same length with corresponding results of
12838// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012839RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012840 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012841 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012842 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012843 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012844
ager@chromium.org357bf652010-04-12 11:30:10 +000012845 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012846}
12847
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012848// Compares 2 strings line-by-line, then token-wise and returns diff in form
12849// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12850// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012851RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012852 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012853 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012854 CONVERT_ARG_CHECKED(String, s1, 0);
12855 CONVERT_ARG_CHECKED(String, s2, 1);
12856
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012857 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012858}
12859
12860
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012861// A testing entry. Returns statement position which is the closest to
12862// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012863RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012864 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012865 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012866 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12867 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12868
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012869 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012870
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012871 if (code->kind() != Code::FUNCTION &&
12872 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012873 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012874 }
12875
12876 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012877 int closest_pc = 0;
12878 int distance = kMaxInt;
12879 while (!it.done()) {
12880 int statement_position = static_cast<int>(it.rinfo()->data());
12881 // Check if this break point is closer that what was previously found.
12882 if (source_position <= statement_position &&
12883 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012884 closest_pc =
12885 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012886 distance = statement_position - source_position;
12887 // Check whether we can't get any closer.
12888 if (distance == 0) break;
12889 }
12890 it.next();
12891 }
12892
12893 return Smi::FromInt(closest_pc);
12894}
12895
12896
ager@chromium.org357bf652010-04-12 11:30:10 +000012897// Calls specified function with or without entering the debugger.
12898// This is used in unit tests to run code as if debugger is entered or simply
12899// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012900RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012901 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012902 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012903 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12904 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12905
12906 Handle<Object> result;
12907 bool pending_exception;
12908 {
12909 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012910 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012911 &pending_exception);
12912 } else {
12913 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012914 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012915 &pending_exception);
12916 }
12917 }
12918 if (!pending_exception) {
12919 return *result;
12920 } else {
12921 return Failure::Exception();
12922 }
12923}
12924
12925
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012926// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012927RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012928 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012929 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012930 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12931 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012932 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012933}
12934
12935
12936// Performs a GC.
12937// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012938RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012939 isolate->heap()->CollectAllGarbage(true, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012940 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012941}
12942
12943
12944// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012945RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012946 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012947 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012948 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012949 }
12950 return Smi::FromInt(usage);
12951}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012952
12953
12954// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012955RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012956#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012957 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012958#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012959 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012960#endif
12961}
12962
12963
12964// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012965RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012966#ifdef LIVE_OBJECT_LIST
12967 return LiveObjectList::Capture();
12968#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012969 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012970#endif
12971}
12972
12973
12974// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012975RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012976#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012977 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012978 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012979 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012980#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012981 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012982#endif
12983}
12984
12985
12986// Generates the response to a debugger request for a dump of the objects
12987// contained in the difference between the captured live object lists
12988// specified by id1 and id2.
12989// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12990// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012991RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012992#ifdef LIVE_OBJECT_LIST
12993 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012994 CONVERT_SMI_ARG_CHECKED(id1, 0);
12995 CONVERT_SMI_ARG_CHECKED(id2, 1);
12996 CONVERT_SMI_ARG_CHECKED(start, 2);
12997 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012998 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12999 EnterDebugger enter_debugger;
13000 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
13001#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013002 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013003#endif
13004}
13005
13006
13007// Gets the specified object as requested by the debugger.
13008// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013009RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013010#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013011 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013012 Object* result = LiveObjectList::GetObj(obj_id);
13013 return result;
13014#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013015 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013016#endif
13017}
13018
13019
13020// Gets the obj id for the specified address if valid.
13021// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013022RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013023#ifdef LIVE_OBJECT_LIST
13024 HandleScope scope;
13025 CONVERT_ARG_CHECKED(String, address, 0);
13026 Object* result = LiveObjectList::GetObjId(address);
13027 return result;
13028#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013029 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013030#endif
13031}
13032
13033
13034// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013035RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013036#ifdef LIVE_OBJECT_LIST
13037 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013038 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013039 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
13040 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
13041 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
13042 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
13043 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
13044
13045 Handle<JSObject> instance_filter;
13046 if (args[1]->IsJSObject()) {
13047 instance_filter = args.at<JSObject>(1);
13048 }
13049 bool verbose = false;
13050 if (args[2]->IsBoolean()) {
13051 verbose = args[2]->IsTrue();
13052 }
13053 int start = 0;
13054 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013055 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013056 }
13057 int limit = Smi::kMaxValue;
13058 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013059 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013060 }
13061
13062 return LiveObjectList::GetObjRetainers(obj_id,
13063 instance_filter,
13064 verbose,
13065 start,
13066 limit,
13067 filter_obj);
13068#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013069 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013070#endif
13071}
13072
13073
13074// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013075RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013076#ifdef LIVE_OBJECT_LIST
13077 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013078 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13079 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013080 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13081
13082 Handle<JSObject> instance_filter;
13083 if (args[2]->IsJSObject()) {
13084 instance_filter = args.at<JSObject>(2);
13085 }
13086
13087 Object* result =
13088 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13089 return result;
13090#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013091 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013092#endif
13093}
13094
13095
13096// Generates the response to a debugger request for a list of all
13097// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013098RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013099#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013100 CONVERT_SMI_ARG_CHECKED(start, 0);
13101 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013102 return LiveObjectList::Info(start, count);
13103#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013104 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013105#endif
13106}
13107
13108
13109// Gets a dump of the specified object as requested by the debugger.
13110// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013111RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013112#ifdef LIVE_OBJECT_LIST
13113 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013114 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013115 Object* result = LiveObjectList::PrintObj(obj_id);
13116 return result;
13117#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013118 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013119#endif
13120}
13121
13122
13123// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013124RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013125#ifdef LIVE_OBJECT_LIST
13126 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013127 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013128#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013129 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013130#endif
13131}
13132
13133
13134// Generates the response to a debugger request for a summary of the types
13135// of objects in the difference between the captured live object lists
13136// specified by id1 and id2.
13137// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13138// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013139RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013140#ifdef LIVE_OBJECT_LIST
13141 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013142 CONVERT_SMI_ARG_CHECKED(id1, 0);
13143 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013144 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13145
13146 EnterDebugger enter_debugger;
13147 return LiveObjectList::Summarize(id1, id2, filter_obj);
13148#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013149 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013150#endif
13151}
13152
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013153#endif // ENABLE_DEBUGGER_SUPPORT
13154
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013156RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013157 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013158 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013159 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013160}
13161
13162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013163RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013164 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013165 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013166 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013167}
13168
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013169
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013170// Finds the script object from the script data. NOTE: This operation uses
13171// heap traversal to find the function generated for the source position
13172// for the requested break point. For lazily compiled functions several heap
13173// traversals might be required rendering this operation as a rather slow
13174// operation. However for setting break points which is normally done through
13175// some kind of user interaction the performance is not crucial.
13176static Handle<Object> Runtime_GetScriptFromScriptName(
13177 Handle<String> script_name) {
13178 // Scan the heap for Script objects to find the script with the requested
13179 // script data.
13180 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013181 script_name->GetHeap()->EnsureHeapIsIterable();
13182 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013183 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013184 HeapObject* obj = NULL;
13185 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013186 // If a script is found check if it has the script data requested.
13187 if (obj->IsScript()) {
13188 if (Script::cast(obj)->name()->IsString()) {
13189 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13190 script = Handle<Script>(Script::cast(obj));
13191 }
13192 }
13193 }
13194 }
13195
13196 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013197 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013198
13199 // Return the script found.
13200 return GetScriptWrapper(script);
13201}
13202
13203
13204// Get the script object from script data. NOTE: Regarding performance
13205// see the NOTE for GetScriptFromScriptData.
13206// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013207RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013208 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013209
13210 ASSERT(args.length() == 1);
13211
13212 CONVERT_CHECKED(String, script_name, args[0]);
13213
13214 // Find the requested script.
13215 Handle<Object> result =
13216 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13217 return *result;
13218}
13219
13220
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013221// Determines whether the given stack frame should be displayed in
13222// a stack trace. The caller is the error constructor that asked
13223// for the stack trace to be collected. The first time a construct
13224// call to this function is encountered it is skipped. The seen_caller
13225// in/out parameter is used to remember if the caller has been seen
13226// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013227static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13228 Object* caller,
13229 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013230 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013231 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013232 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013233 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013234 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13235 Object* raw_fun = frame->function();
13236 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013237 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013238 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013239 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013240 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013241 *seen_caller = true;
13242 return false;
13243 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013244 // Skip all frames until we've seen the caller.
13245 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013246 // Also, skip non-visible built-in functions and any call with the builtins
13247 // object as receiver, so as to not reveal either the builtins object or
13248 // an internal function.
13249 // The --builtins-in-stack-traces command line flag allows including
13250 // internal call sites in the stack trace for debugging purposes.
13251 if (!FLAG_builtins_in_stack_traces) {
13252 JSFunction* fun = JSFunction::cast(raw_fun);
13253 if (frame->receiver()->IsJSBuiltinsObject() ||
13254 (fun->IsBuiltin() && !fun->shared()->native())) {
13255 return false;
13256 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013257 }
13258 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013259}
13260
13261
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013262// Collect the raw data for a stack trace. Returns an array of 4
13263// element segments each containing a receiver, function, code and
13264// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013265RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013266 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013267 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013268 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13269
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013270 HandleScope scope(isolate);
13271 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013272
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013273 limit = Max(limit, 0); // Ensure that limit is not negative.
13274 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013275 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013276 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013277
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013278 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013279 // If the caller parameter is a function we skip frames until we're
13280 // under it before starting to collect.
13281 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013282 int cursor = 0;
13283 int frames_seen = 0;
13284 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013285 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013286 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013287 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013288 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013289 // Set initial size to the maximum inlining level + 1 for the outermost
13290 // function.
13291 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013292 frame->Summarize(&frames);
13293 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013294 if (cursor + 4 > elements->length()) {
13295 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13296 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013297 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013298 for (int i = 0; i < cursor; i++) {
13299 new_elements->set(i, elements->get(i));
13300 }
13301 elements = new_elements;
13302 }
13303 ASSERT(cursor + 4 <= elements->length());
13304
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013305 Handle<Object> recv = frames[i].receiver();
13306 Handle<JSFunction> fun = frames[i].function();
13307 Handle<Code> code = frames[i].code();
13308 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013309 elements->set(cursor++, *recv);
13310 elements->set(cursor++, *fun);
13311 elements->set(cursor++, *code);
13312 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013313 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013314 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013315 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013316 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013317 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013318 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013319 return *result;
13320}
13321
13322
ager@chromium.org3811b432009-10-28 14:53:37 +000013323// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013324RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013325 ASSERT_EQ(args.length(), 0);
13326
13327 NoHandleAllocation ha;
13328
13329 const char* version_string = v8::V8::GetVersion();
13330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013331 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13332 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013333}
13334
13335
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013336RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013337 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013338 OS::PrintError("abort: %s\n",
13339 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013340 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013341 OS::Abort();
13342 UNREACHABLE();
13343 return NULL;
13344}
13345
13346
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013347RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013348 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013349 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013350 Object* key = args[1];
13351
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013352 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013353 Object* o = cache->get(finger_index);
13354 if (o == key) {
13355 // The fastest case: hit the same place again.
13356 return cache->get(finger_index + 1);
13357 }
13358
13359 for (int i = finger_index - 2;
13360 i >= JSFunctionResultCache::kEntriesIndex;
13361 i -= 2) {
13362 o = cache->get(i);
13363 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013364 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013365 return cache->get(i + 1);
13366 }
13367 }
13368
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013369 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013370 ASSERT(size <= cache->length());
13371
13372 for (int i = size - 2; i > finger_index; i -= 2) {
13373 o = cache->get(i);
13374 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013375 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013376 return cache->get(i + 1);
13377 }
13378 }
13379
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013380 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013381 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013382
13383 Handle<JSFunctionResultCache> cache_handle(cache);
13384 Handle<Object> key_handle(key);
13385 Handle<Object> value;
13386 {
13387 Handle<JSFunction> factory(JSFunction::cast(
13388 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13389 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013390 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013391 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013392 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013393 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013394 value = Execution::Call(factory,
13395 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013396 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013397 argv,
13398 &pending_exception);
13399 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013400 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013401
13402#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013403 if (FLAG_verify_heap) {
13404 cache_handle->JSFunctionResultCacheVerify();
13405 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013406#endif
13407
13408 // Function invocation may have cleared the cache. Reread all the data.
13409 finger_index = cache_handle->finger_index();
13410 size = cache_handle->size();
13411
13412 // If we have spare room, put new data into it, otherwise evict post finger
13413 // entry which is likely to be the least recently used.
13414 int index = -1;
13415 if (size < cache_handle->length()) {
13416 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13417 index = size;
13418 } else {
13419 index = finger_index + JSFunctionResultCache::kEntrySize;
13420 if (index == cache_handle->length()) {
13421 index = JSFunctionResultCache::kEntriesIndex;
13422 }
13423 }
13424
13425 ASSERT(index % 2 == 0);
13426 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13427 ASSERT(index < cache_handle->length());
13428
13429 cache_handle->set(index, *key_handle);
13430 cache_handle->set(index + 1, *value);
13431 cache_handle->set_finger_index(index);
13432
13433#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013434 if (FLAG_verify_heap) {
13435 cache_handle->JSFunctionResultCacheVerify();
13436 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013437#endif
13438
13439 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013440}
13441
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013442
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013443RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013444 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013445 CONVERT_ARG_CHECKED(String, type, 0);
13446 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013447 return *isolate->factory()->NewJSMessageObject(
13448 type,
13449 arguments,
13450 0,
13451 0,
13452 isolate->factory()->undefined_value(),
13453 isolate->factory()->undefined_value(),
13454 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013455}
13456
13457
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013458RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013459 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13460 return message->type();
13461}
13462
13463
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013464RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013465 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13466 return message->arguments();
13467}
13468
13469
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013470RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013471 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13472 return Smi::FromInt(message->start_position());
13473}
13474
13475
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013476RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013477 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13478 return message->script();
13479}
13480
13481
kasper.lund44510672008-07-25 07:37:58 +000013482#ifdef DEBUG
13483// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13484// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013485RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013486 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013487 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013488#define COUNT_ENTRY(Name, argc, ressize) + 1
13489 int entry_count = 0
13490 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13491 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13492 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13493#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013494 Factory* factory = isolate->factory();
13495 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013496 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013497 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013498#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013499 { \
13500 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013501 Handle<String> name; \
13502 /* Inline runtime functions have an underscore in front of the name. */ \
13503 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013504 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013505 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13506 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013507 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013508 Vector<const char>(#Name, StrLength(#Name))); \
13509 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013510 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013511 pair_elements->set(0, *name); \
13512 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013513 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013514 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013515 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013516 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013517 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013518 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013519 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013520 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013521#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013522 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013523 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013524 return *result;
13525}
kasper.lund44510672008-07-25 07:37:58 +000013526#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013527
13528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013529RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013530 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013531 CONVERT_CHECKED(String, format, args[0]);
13532 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013533 String::FlatContent format_content = format->GetFlatContent();
13534 RUNTIME_ASSERT(format_content.IsAscii());
13535 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013536 LOGGER->LogRuntime(chars, elms);
13537 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013538}
13539
13540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013541RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013542 UNREACHABLE(); // implemented as macro in the parser
13543 return NULL;
13544}
13545
13546
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013547#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13548 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13549 CONVERT_CHECKED(JSObject, obj, args[0]); \
13550 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13551 }
13552
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013553ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013554ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13555ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13556ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13557ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13558ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13559ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13560ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13561ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13562ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13563ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13564ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13565ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13566ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13567
13568#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13569
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013570
13571RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13572 ASSERT(args.length() == 2);
13573 CONVERT_CHECKED(JSObject, obj1, args[0]);
13574 CONVERT_CHECKED(JSObject, obj2, args[1]);
13575 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13576}
13577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013578// ----------------------------------------------------------------------------
13579// Implementation of Runtime
13580
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013581#define F(name, number_of_args, result_size) \
13582 { Runtime::k##name, Runtime::RUNTIME, #name, \
13583 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013584
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013585
13586#define I(name, number_of_args, result_size) \
13587 { Runtime::kInline##name, Runtime::INLINE, \
13588 "_" #name, NULL, number_of_args, result_size },
13589
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013590static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013591 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013592 INLINE_FUNCTION_LIST(I)
13593 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013594};
13595
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013596
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013597MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13598 Object* dictionary) {
13599 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013600 ASSERT(dictionary != NULL);
13601 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13602 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013603 Object* name_symbol;
13604 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013605 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013606 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13607 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013608 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013609 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13610 String::cast(name_symbol),
13611 Smi::FromInt(i),
13612 PropertyDetails(NONE, NORMAL));
13613 if (!maybe_dictionary->ToObject(&dictionary)) {
13614 // Non-recoverable failure. Calling code must restart heap
13615 // initialization.
13616 return maybe_dictionary;
13617 }
13618 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013619 }
13620 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013621}
13622
13623
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013624const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13625 Heap* heap = name->GetHeap();
13626 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013627 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013628 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013629 int function_index = Smi::cast(smi_index)->value();
13630 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013631 }
13632 return NULL;
13633}
13634
13635
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013636const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013637 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13638}
13639
13640
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013641void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013642 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013643 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013644 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013645 if (isolate->heap()->new_space()->AddFreshPage()) {
13646 return;
13647 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013648 // Try to do a garbage collection; ignore it if it fails. The C
13649 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013650 isolate->heap()->CollectGarbage(failure->allocation_space(),
13651 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013652 } else {
13653 // Handle last resort GC and make sure to allow future allocations
13654 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013655 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013656 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13657 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013658 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013659}
13660
13661
13662} } // namespace v8::internal