blob: b9ec719806f420e7d59efbfcfc0cdf7f8b3cc57e [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
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000431static const int kSmiOnlyLiteralMinimumLength = 1024;
432
433
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000434Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000436 Handle<FixedArray> literals,
437 Handle<FixedArray> elements) {
438 // Create the JSArray.
439 Handle<JSFunction> constructor(
440 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000441 Handle<JSArray> object =
442 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000443
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000444 ElementsKind constant_elements_kind =
445 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
446 Handle<FixedArrayBase> constant_elements_values(
447 FixedArrayBase::cast(elements->get(1)));
448
449 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
450 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
451 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
452 constant_elements_kind > object->GetElementsKind();
453
454 if (!FLAG_smi_only_arrays &&
455 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
456 constant_elements_kind != object->GetElementsKind()) {
457 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000458 }
459
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000460 // If the ElementsKind of the constant values of the array literal are less
461 // specific than the ElementsKind of the boilerplate array object, change the
462 // boilerplate array object's map to reflect that kind.
463 if (allow_literal_kind_transition) {
464 Handle<Map> transitioned_array_map =
465 isolate->factory()->GetElementsTransitionMap(object,
466 constant_elements_kind);
467 object->set_map(*transitioned_array_map);
468 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000470 Handle<FixedArrayBase> copied_elements_values;
471 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
472 ASSERT(FLAG_smi_only_arrays);
473 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
474 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000475 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000476 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
477 constant_elements_kind == FAST_ELEMENTS);
478 const bool is_cow =
479 (constant_elements_values->map() ==
480 isolate->heap()->fixed_cow_array_map());
481 if (is_cow) {
482 copied_elements_values = constant_elements_values;
483#if DEBUG
484 Handle<FixedArray> fixed_array_values =
485 Handle<FixedArray>::cast(copied_elements_values);
486 for (int i = 0; i < fixed_array_values->length(); i++) {
487 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
488 }
489#endif
490 } else {
491 Handle<FixedArray> fixed_array_values =
492 Handle<FixedArray>::cast(constant_elements_values);
493 Handle<FixedArray> fixed_array_values_copy =
494 isolate->factory()->CopyFixedArray(fixed_array_values);
495 copied_elements_values = fixed_array_values_copy;
496 for (int i = 0; i < fixed_array_values->length(); i++) {
497 Object* current = fixed_array_values->get(i);
498 if (current->IsFixedArray()) {
499 // The value contains the constant_properties of a
500 // simple object or array literal.
501 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
502 Handle<Object> result =
503 CreateLiteralBoilerplate(isolate, literals, fa);
504 if (result.is_null()) return result;
505 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000506 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000507 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000508 }
509 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000510 object->set_elements(*copied_elements_values);
511 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 return object;
513}
514
515
516static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000517 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000518 Handle<FixedArray> literals,
519 Handle<FixedArray> array) {
520 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000523 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 return CreateObjectLiteralBoilerplate(isolate,
525 literals,
526 elements,
527 true,
528 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000529 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 return CreateObjectLiteralBoilerplate(isolate,
531 literals,
532 elements,
533 false,
534 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000535 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000536 return Runtime::CreateArrayLiteralBoilerplate(
537 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000538 default:
539 UNREACHABLE();
540 return Handle<Object>::null();
541 }
542}
543
544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000545RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000547 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000548 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000549 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000551 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
553 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000554
555 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 Handle<Object> boilerplate(literals->get(literals_index), isolate);
557 if (*boilerplate == isolate->heap()->undefined_value()) {
558 boilerplate = CreateObjectLiteralBoilerplate(isolate,
559 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000560 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000561 should_have_fast_elements,
562 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000563 if (boilerplate.is_null()) return Failure::Exception();
564 // Update the functions literal and return the boilerplate.
565 literals->set(literals_index, *boilerplate);
566 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000568}
569
570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000571RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000573 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000575 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000577 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
579 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580
581 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 Handle<Object> boilerplate(literals->get(literals_index), isolate);
583 if (*boilerplate == isolate->heap()->undefined_value()) {
584 boilerplate = CreateObjectLiteralBoilerplate(isolate,
585 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000586 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 should_have_fast_elements,
588 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589 if (boilerplate.is_null()) return Failure::Exception();
590 // Update the functions literal and return the boilerplate.
591 literals->set(literals_index, *boilerplate);
592 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000593 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000594}
595
596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000597RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000599 ASSERT(args.length() == 3);
600 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000601 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
603
604 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000605 Handle<Object> boilerplate(literals->get(literals_index), isolate);
606 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000607 boilerplate =
608 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000609 if (boilerplate.is_null()) return Failure::Exception();
610 // Update the functions literal and return the boilerplate.
611 literals->set(literals_index, *boilerplate);
612 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614}
615
616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000617RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619 ASSERT(args.length() == 3);
620 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000621 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000622 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
623
624 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000625 Handle<Object> boilerplate(literals->get(literals_index), isolate);
626 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000627 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000628 boilerplate =
629 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000630 if (boilerplate.is_null()) return Failure::Exception();
631 // Update the functions literal and return the boilerplate.
632 literals->set(literals_index, *boilerplate);
633 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000634 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000636 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000637 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000639}
640
641
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000642RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
643 ASSERT(args.length() == 2);
644 Object* handler = args[0];
645 Object* prototype = args[1];
646 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000647 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000648 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
649}
650
651
lrn@chromium.org34e60782011-09-15 07:25:40 +0000652RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
653 ASSERT(args.length() == 4);
654 Object* handler = args[0];
655 Object* call_trap = args[1];
656 Object* construct_trap = args[2];
657 Object* prototype = args[3];
658 Object* used_prototype =
659 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
660 return isolate->heap()->AllocateJSFunctionProxy(
661 handler, call_trap, construct_trap, used_prototype);
662}
663
664
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000665RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
666 ASSERT(args.length() == 1);
667 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000668 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669}
670
671
lrn@chromium.org34e60782011-09-15 07:25:40 +0000672RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
673 ASSERT(args.length() == 1);
674 Object* obj = args[0];
675 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
676}
677
678
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000679RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
680 ASSERT(args.length() == 1);
681 CONVERT_CHECKED(JSProxy, proxy, args[0]);
682 return proxy->handler();
683}
684
685
lrn@chromium.org34e60782011-09-15 07:25:40 +0000686RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
687 ASSERT(args.length() == 1);
688 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
689 return proxy->call_trap();
690}
691
692
693RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
694 ASSERT(args.length() == 1);
695 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
696 return proxy->construct_trap();
697}
698
699
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000700RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
701 ASSERT(args.length() == 1);
702 CONVERT_CHECKED(JSProxy, proxy, args[0]);
703 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000704 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000705}
706
707
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
709 HandleScope scope(isolate);
710 ASSERT(args.length() == 1);
711 CONVERT_ARG_CHECKED(JSSet, holder, 0);
712 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
713 holder->set_table(*table);
714 return *holder;
715}
716
717
718RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
719 HandleScope scope(isolate);
720 ASSERT(args.length() == 2);
721 CONVERT_ARG_CHECKED(JSSet, holder, 0);
722 Handle<Object> key(args[1]);
723 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
724 table = ObjectHashSetAdd(table, key);
725 holder->set_table(*table);
726 return isolate->heap()->undefined_symbol();
727}
728
729
730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 2);
733 CONVERT_ARG_CHECKED(JSSet, holder, 0);
734 Handle<Object> key(args[1]);
735 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
736 return isolate->heap()->ToBoolean(table->Contains(*key));
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
743 CONVERT_ARG_CHECKED(JSSet, holder, 0);
744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetRemove(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 1);
755 CONVERT_ARG_CHECKED(JSMap, holder, 0);
756 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
757 holder->set_table(*table);
758 return *holder;
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
765 CONVERT_ARG_CHECKED(JSMap, holder, 0);
766 Handle<Object> key(args[1]);
767 return ObjectHashTable::cast(holder->table())->Lookup(*key);
768}
769
770
771RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
772 HandleScope scope(isolate);
773 ASSERT(args.length() == 3);
774 CONVERT_ARG_CHECKED(JSMap, holder, 0);
775 Handle<Object> key(args[1]);
776 Handle<Object> value(args[2]);
777 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
778 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
779 holder->set_table(*new_table);
780 return *value;
781}
782
783
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000784RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 1);
787 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
788 ASSERT(weakmap->map()->inobject_properties() == 0);
789 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
790 weakmap->set_table(*table);
791 weakmap->set_next(Smi::FromInt(0));
792 return *weakmap;
793}
794
795
796RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
797 NoHandleAllocation ha;
798 ASSERT(args.length() == 2);
799 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000800 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
801 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000802}
803
804
805RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
806 HandleScope scope(isolate);
807 ASSERT(args.length() == 3);
808 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000809 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000811 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000812 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
813 weakmap->set_table(*new_table);
814 return *value;
815}
816
817
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000818RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819 NoHandleAllocation ha;
820 ASSERT(args.length() == 1);
821 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000822 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 return JSObject::cast(obj)->class_name();
824}
825
ager@chromium.org7c537e22008-10-16 08:43:32 +0000826
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000827RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
828 NoHandleAllocation ha;
829 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000830 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
831 Object* obj = input_obj;
832 // We don't expect access checks to be needed on JSProxy objects.
833 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000834 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000835 if (obj->IsAccessCheckNeeded() &&
836 !isolate->MayNamedAccess(JSObject::cast(obj),
837 isolate->heap()->Proto_symbol(),
838 v8::ACCESS_GET)) {
839 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
840 return isolate->heap()->undefined_value();
841 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000842 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000843 } while (obj->IsJSObject() &&
844 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000845 return obj;
846}
847
848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000850 NoHandleAllocation ha;
851 ASSERT(args.length() == 2);
852 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
853 Object* O = args[0];
854 Object* V = args[1];
855 while (true) {
856 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000857 if (prototype->IsNull()) return isolate->heap()->false_value();
858 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859 V = prototype;
860 }
861}
862
863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000864RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000865 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000866 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000867 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000868 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869}
870
871
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000872// Recursively traverses hidden prototypes if property is not found
873static void GetOwnPropertyImplementation(JSObject* obj,
874 String* name,
875 LookupResult* result) {
876 obj->LocalLookupRealNamedProperty(name, result);
877
878 if (!result->IsProperty()) {
879 Object* proto = obj->GetPrototype();
880 if (proto->IsJSObject() &&
881 JSObject::cast(proto)->map()->is_hidden_prototype())
882 GetOwnPropertyImplementation(JSObject::cast(proto),
883 name, result);
884 }
885}
886
887
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000888static bool CheckAccessException(LookupResult* result,
889 v8::AccessType access_type) {
890 if (result->type() == CALLBACKS) {
891 Object* callback = result->GetCallbackObject();
892 if (callback->IsAccessorInfo()) {
893 AccessorInfo* info = AccessorInfo::cast(callback);
894 bool can_access =
895 (access_type == v8::ACCESS_HAS &&
896 (info->all_can_read() || info->all_can_write())) ||
897 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
898 (access_type == v8::ACCESS_SET && info->all_can_write());
899 return can_access;
900 }
901 }
902
903 return false;
904}
905
906
907static bool CheckAccess(JSObject* obj,
908 String* name,
909 LookupResult* result,
910 v8::AccessType access_type) {
911 ASSERT(result->IsProperty());
912
913 JSObject* holder = result->holder();
914 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000915 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000916 while (true) {
917 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000919 // Access check callback denied the access, but some properties
920 // can have a special permissions which override callbacks descision
921 // (currently see v8::AccessControl).
922 break;
923 }
924
925 if (current == holder) {
926 return true;
927 }
928
929 current = JSObject::cast(current->GetPrototype());
930 }
931
932 // API callbacks can have per callback access exceptions.
933 switch (result->type()) {
934 case CALLBACKS: {
935 if (CheckAccessException(result, access_type)) {
936 return true;
937 }
938 break;
939 }
940 case INTERCEPTOR: {
941 // If the object has an interceptor, try real named properties.
942 // Overwrite the result to fetch the correct property later.
943 holder->LookupRealNamedProperty(name, result);
944 if (result->IsProperty()) {
945 if (CheckAccessException(result, access_type)) {
946 return true;
947 }
948 }
949 break;
950 }
951 default:
952 break;
953 }
954
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000955 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000956 return false;
957}
958
959
960// TODO(1095): we should traverse hidden prototype hierachy as well.
961static bool CheckElementAccess(JSObject* obj,
962 uint32_t index,
963 v8::AccessType access_type) {
964 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000966 return false;
967 }
968
969 return true;
970}
971
972
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000973// Enumerator used as indices into the array returned from GetOwnProperty
974enum PropertyDescriptorIndices {
975 IS_ACCESSOR_INDEX,
976 VALUE_INDEX,
977 GETTER_INDEX,
978 SETTER_INDEX,
979 WRITABLE_INDEX,
980 ENUMERABLE_INDEX,
981 CONFIGURABLE_INDEX,
982 DESCRIPTOR_SIZE
983};
984
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000985// Returns an array with the property description:
986// if args[1] is not a property on args[0]
987// returns undefined
988// if args[1] is a data property on args[0]
989// [false, value, Writeable, Enumerable, Configurable]
990// if args[1] is an accessor on args[0]
991// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000992RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000993 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 Heap* heap = isolate->heap();
995 HandleScope scope(isolate);
996 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
997 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000998 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000999 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1000 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001001
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001002 // This could be an element.
1003 uint32_t index;
1004 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001005 switch (obj->HasLocalElement(index)) {
1006 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001007 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001008
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001009 case JSObject::STRING_CHARACTER_ELEMENT: {
1010 // Special handling of string objects according to ECMAScript 5
1011 // 15.5.5.2. Note that this might be a string object with elements
1012 // other than the actual string value. This is covered by the
1013 // subsequent cases.
1014 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1015 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001016 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001018 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001019 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 elms->set(WRITABLE_INDEX, heap->false_value());
1021 elms->set(ENUMERABLE_INDEX, heap->false_value());
1022 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001023 return *desc;
1024 }
1025
1026 case JSObject::INTERCEPTED_ELEMENT:
1027 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001028 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001029 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001030 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001031 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 elms->set(WRITABLE_INDEX, heap->true_value());
1033 elms->set(ENUMERABLE_INDEX, heap->true_value());
1034 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001035 return *desc;
1036 }
1037
1038 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001039 Handle<JSObject> holder = obj;
1040 if (obj->IsJSGlobalProxy()) {
1041 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001043 ASSERT(proto->IsJSGlobalObject());
1044 holder = Handle<JSObject>(JSObject::cast(proto));
1045 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001046 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001047 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001048 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001049 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001050 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001051 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001052 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001053 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001055 PropertyDetails details = dictionary->DetailsAt(entry);
1056 switch (details.type()) {
1057 case CALLBACKS: {
1058 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001059 AccessorPair* accessors =
1060 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001061 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001062 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001063 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001064 }
1065 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001066 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001067 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001068 break;
1069 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001070 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001071 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001073 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001074 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001077 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001078 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001079 default:
1080 UNREACHABLE();
1081 break;
1082 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1084 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001085 return *desc;
1086 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001087 }
1088 }
1089
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001090 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001091 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001092
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001093 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001094 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001095 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001096
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001097 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001099 }
1100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1102 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001103
1104 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001105 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001106
1107 if (is_js_accessor) {
1108 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001109 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001110
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001111 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001112 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001113 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001114 }
1115 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001116 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001117 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001118 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1120 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001121
1122 PropertyAttributes attrs;
1123 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001124 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001125 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1126 if (!maybe_value->ToObject(&value)) return maybe_value;
1127 }
1128 elms->set(VALUE_INDEX, value);
1129 }
1130
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001131 return *desc;
1132}
1133
1134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001135RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001136 ASSERT(args.length() == 1);
1137 CONVERT_CHECKED(JSObject, obj, args[0]);
1138 return obj->PreventExtensions();
1139}
1140
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001142RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001143 ASSERT(args.length() == 1);
1144 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001145 if (obj->IsJSGlobalProxy()) {
1146 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001147 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001148 ASSERT(proto->IsJSGlobalObject());
1149 obj = JSObject::cast(proto);
1150 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001151 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001152}
1153
1154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001155RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001156 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001158 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1159 CONVERT_ARG_CHECKED(String, pattern, 1);
1160 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001161 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1162 if (result.is_null()) return Failure::Exception();
1163 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001164}
1165
1166
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001167RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001169 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001170 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001171 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172}
1173
1174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001175RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176 ASSERT(args.length() == 1);
1177 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001178 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001179 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180}
1181
1182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001183RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 ASSERT(args.length() == 2);
1185 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001186 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001187 int index = field->value();
1188 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1189 InstanceType type = templ->map()->instance_type();
1190 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1191 type == OBJECT_TEMPLATE_INFO_TYPE);
1192 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001193 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001194 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1195 } else {
1196 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1197 }
1198 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001199}
1200
1201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001202RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001203 ASSERT(args.length() == 1);
1204 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001205 Map* old_map = object->map();
1206 bool needs_access_checks = old_map->is_access_check_needed();
1207 if (needs_access_checks) {
1208 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001209 Object* new_map;
1210 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1211 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1212 }
ager@chromium.org32912102009-01-16 10:38:43 +00001213
1214 Map::cast(new_map)->set_is_access_check_needed(false);
1215 object->set_map(Map::cast(new_map));
1216 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001217 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001218}
1219
1220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001221RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001222 ASSERT(args.length() == 1);
1223 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001224 Map* old_map = object->map();
1225 if (!old_map->is_access_check_needed()) {
1226 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001227 Object* new_map;
1228 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1229 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1230 }
ager@chromium.org32912102009-01-16 10:38:43 +00001231
1232 Map::cast(new_map)->set_is_access_check_needed(true);
1233 object->set_map(Map::cast(new_map));
1234 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001235 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001236}
1237
1238
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001239static Failure* ThrowRedeclarationError(Isolate* isolate,
1240 const char* type,
1241 Handle<String> name) {
1242 HandleScope scope(isolate);
1243 Handle<Object> type_handle =
1244 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245 Handle<Object> args[2] = { type_handle, name };
1246 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1248 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249}
1250
1251
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001252RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001253 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001254 HandleScope scope(isolate);
1255 Handle<GlobalObject> global = Handle<GlobalObject>(
1256 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257
ager@chromium.org3811b432009-10-28 14:53:37 +00001258 Handle<Context> context = args.at<Context>(0);
1259 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001260 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262 // Traverse the name/value pairs and set the properties.
1263 int length = pairs->length();
1264 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001265 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268
1269 // We have to declare a global const property. To capture we only
1270 // assign to it when evaluating the assignment for "const x =
1271 // <expr>" the initial value is the hole.
1272 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 if (value->IsUndefined() || is_const_property) {
1275 // Lookup the property in the global object, and don't set the
1276 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001277 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 global->Lookup(*name, &lookup);
1279 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001280 // We found an existing property. Unless it was an interceptor
1281 // that claims the property is absent, skip this declaration.
1282 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 continue;
1284 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001285 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1286 if (attributes != ABSENT) {
1287 continue;
1288 }
1289 // Fall-through and introduce the absent property by using
1290 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291 }
1292 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001293 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001295 Handle<SharedFunctionInfo> shared =
1296 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001298 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1299 context,
1300 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001301 value = function;
1302 }
1303
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001304 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 global->LocalLookup(*name, &lookup);
1306
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001307 // Compute the property attributes. According to ECMA-262, section
1308 // 13, page 71, the property must be read-only and
1309 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1310 // property as read-only, so we don't either.
1311 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001312 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001313 attr |= DONT_DELETE;
1314 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001315 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001316 if (is_const_property || (is_native && is_function_declaration)) {
1317 attr |= READ_ONLY;
1318 }
1319
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001320 // Safari does not allow the invocation of callback setters for
1321 // function declarations. To mimic this behavior, we do not allow
1322 // the invocation of setters for function values. This makes a
1323 // difference for global functions with the same names as event
1324 // handlers such as "function onload() {}". Firefox does call the
1325 // onload setter in those case and Safari does not. We follow
1326 // Safari for compatibility.
1327 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001328 // Do not change DONT_DELETE to false from true.
1329 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001330 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001331 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001332 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1333
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001334 RETURN_IF_EMPTY_HANDLE(
1335 isolate,
1336 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1337 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001339 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1340 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1341 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001342 RETURN_IF_EMPTY_HANDLE(
1343 isolate,
1344 JSReceiver::SetProperty(global, name, value,
1345 static_cast<PropertyAttributes>(attr),
1346 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 }
1348 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001350 ASSERT(!isolate->has_pending_exception());
1351 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352}
1353
1354
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001355RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001356 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001357 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001359 // Declarations are always made in a function or global context. In the
1360 // case of eval code, the context passed is the context of the caller,
1361 // which may be some nested context and not the declaration context.
1362 RUNTIME_ASSERT(args[0]->IsContext());
1363 Handle<Context> context(Context::cast(args[0])->declaration_context());
1364
ager@chromium.org7c537e22008-10-16 08:43:32 +00001365 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001366 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001367 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001368 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 int index;
1371 PropertyAttributes attributes;
1372 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001373 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001374 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001375 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376
1377 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001378 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001379 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1380 // Functions are not read-only.
1381 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1382 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001383 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001384 }
1385
1386 // Initialize it if necessary.
1387 if (*initial_value != NULL) {
1388 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001389 ASSERT(holder.is_identical_to(context));
1390 if (((attributes & READ_ONLY) == 0) ||
1391 context->get(index)->IsTheHole()) {
1392 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393 }
1394 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001395 // Slow case: The property is in the context extension object of a
1396 // function context or the global object of a global context.
1397 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001398 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001399 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001400 JSReceiver::SetProperty(object, name, initial_value, mode,
1401 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 }
1403 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001406 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 // "declared" in the function context's extension context or as a
1408 // property of the the global object.
1409 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001410 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001411 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001412 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001413 // Context extension objects are allocated lazily.
1414 ASSERT(context->IsFunctionContext());
1415 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001416 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001417 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001418 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001419 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420
ager@chromium.org7c537e22008-10-16 08:43:32 +00001421 // Declare the property by setting it to the initial value if provided,
1422 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1423 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001426 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001427 // Declaring a const context slot is a conflicting declaration if
1428 // there is a callback with that name in a prototype. It is
1429 // allowed to introduce const variables in
1430 // JSContextExtensionObjects. They are treated specially in
1431 // SetProperty and no setters are invoked for those since they are
1432 // not real JSObjects.
1433 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001434 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001435 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001437 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001438 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001439 }
1440 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001441 RETURN_IF_EMPTY_HANDLE(
1442 isolate,
1443 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001444 }
1445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447}
1448
1449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001450RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001451 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001452 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001453 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001454 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001455
1456 // Determine if we need to assign to the variable if it already
1457 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001458 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1459 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001462 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001464 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1465 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1466 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467
1468 // According to ECMA-262, section 12.2, page 62, the property must
1469 // not be deletable.
1470 PropertyAttributes attributes = DONT_DELETE;
1471
1472 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001473 // there, there is a property with this name in the prototype chain.
1474 // We follow Safari and Firefox behavior and only set the property
1475 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001476 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001477 // Note that objects can have hidden prototypes, so we need to traverse
1478 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001479 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001480 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001481 while (object->IsJSObject() &&
1482 JSObject::cast(object)->map()->is_hidden_prototype()) {
1483 JSObject* raw_holder = JSObject::cast(object);
1484 raw_holder->LocalLookup(*name, &lookup);
1485 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1486 HandleScope handle_scope(isolate);
1487 Handle<JSObject> holder(raw_holder);
1488 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1489 // Update the raw pointer in case it's changed due to GC.
1490 raw_holder = *holder;
1491 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1492 // Found an interceptor that's not read only.
1493 if (assign) {
1494 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001495 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001496 } else {
1497 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001498 }
1499 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001500 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 }
1503
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001504 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001505 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001506 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001507 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001508 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001509 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510}
1511
1512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001513RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 // All constants are declared with an initial value. The name
1515 // of the constant is the first argument and the initial value
1516 // is the second.
1517 RUNTIME_ASSERT(args.length() == 2);
1518 CONVERT_ARG_CHECKED(String, name, 0);
1519 Handle<Object> value = args.at<Object>(1);
1520
1521 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001522 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001523
1524 // According to ECMA-262, section 12.2, page 62, the property must
1525 // not be deletable. Since it's a const, it must be READ_ONLY too.
1526 PropertyAttributes attributes =
1527 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1528
1529 // Lookup the property locally in the global object. If it isn't
1530 // there, we add the property and take special precautions to always
1531 // add it as a local property even in case of callbacks in the
1532 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001533 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001534 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 global->LocalLookup(*name, &lookup);
1536 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001537 return global->SetLocalPropertyIgnoreAttributes(*name,
1538 *value,
1539 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 }
1541
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001544 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001545 HandleScope handle_scope(isolate);
1546 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001548 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549 // property through an interceptor and only do it if it's
1550 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001551 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001552 RETURN_IF_EMPTY_HANDLE(
1553 isolate,
1554 JSReceiver::SetProperty(global, name, value, attributes,
1555 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 return *value;
1557 }
1558
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001559 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 // constant. For now, we determine this by checking if the
1561 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001562 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 PropertyType type = lookup.type();
1564 if (type == FIELD) {
1565 FixedArray* properties = global->properties();
1566 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001567 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 properties->set(index, *value);
1569 }
1570 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001571 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1572 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001573 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 }
1575 } else {
1576 // Ignore re-initialization of constants that have already been
1577 // assigned a function value.
1578 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1579 }
1580
1581 // Use the set value as the result of the operation.
1582 return *value;
1583}
1584
1585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001586RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001587 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 ASSERT(args.length() == 3);
1589
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001590 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001593 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001594 RUNTIME_ASSERT(args[1]->IsContext());
1595 Handle<Context> context(Context::cast(args[1])->declaration_context());
1596
1597 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598
1599 int index;
1600 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001601 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001602 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001603 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001604 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001606 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001607 ASSERT(holder->IsContext());
1608 // Property was found in a context. Perform the assignment if we
1609 // found some non-constant or an uninitialized constant.
1610 Handle<Context> context = Handle<Context>::cast(holder);
1611 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1612 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 }
1614 return *value;
1615 }
1616
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001617 // The property could not be found, we introduce it as a property of the
1618 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001619 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 Handle<JSObject> global = Handle<JSObject>(
1621 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001622 // Strict mode not needed (const disallowed in strict mode).
1623 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001624 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001625 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001626 return *value;
1627 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001629 // The property was present in some function's context extension object,
1630 // as a property on the subject of a with, or as a property of the global
1631 // object.
1632 //
1633 // In most situations, eval-introduced consts should still be present in
1634 // the context extension object. However, because declaration and
1635 // initialization are separate, the property might have been deleted
1636 // before we reach the initialization point.
1637 //
1638 // Example:
1639 //
1640 // function f() { eval("delete x; const x;"); }
1641 //
1642 // In that case, the initialization behaves like a normal assignment.
1643 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001644
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001645 if (*object == context->extension()) {
1646 // This is the property that was introduced by the const declaration.
1647 // Set it if it hasn't been set before. NOTE: We cannot use
1648 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001649 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001650 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001651 ASSERT(lookup.IsProperty()); // the property was declared
1652 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1653
1654 PropertyType type = lookup.type();
1655 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001656 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001657 int index = lookup.GetFieldIndex();
1658 if (properties->get(index)->IsTheHole()) {
1659 properties->set(index, *value);
1660 }
1661 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001662 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1663 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001664 }
1665 } else {
1666 // We should not reach here. Any real, named property should be
1667 // either a field or a dictionary slot.
1668 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669 }
1670 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001671 // The property was found on some other object. Set it if it is not a
1672 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001673 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001674 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001675 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001676 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001677 JSReceiver::SetProperty(object, name, value, attributes,
1678 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001679 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001680 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682 return *value;
1683}
1684
1685
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001686RUNTIME_FUNCTION(MaybeObject*,
1687 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001689 ASSERT(args.length() == 2);
1690 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001691 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001692 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001693 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001694 }
1695 return *object;
1696}
1697
1698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001699RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001701 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001702 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1703 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001704 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001705 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001706 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001707 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001708 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001709 RUNTIME_ASSERT(index >= 0);
1710 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001712 Handle<Object> result = RegExpImpl::Exec(regexp,
1713 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001714 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001715 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001716 if (result.is_null()) return Failure::Exception();
1717 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001718}
1719
1720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001721RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001722 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001723 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001724 if (elements_count < 0 ||
1725 elements_count > FixedArray::kMaxLength ||
1726 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001728 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 Object* new_object;
1730 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001732 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1733 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001734 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001735 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1736 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001737 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1738 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001739 {
1740 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001742 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001744 }
1745 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001747 array->set_elements(elements);
1748 array->set_length(Smi::FromInt(elements_count));
1749 // Write in-object properties after the length of the array.
1750 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1751 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1752 return array;
1753}
1754
1755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001756RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001757 AssertNoAllocation no_alloc;
1758 ASSERT(args.length() == 5);
1759 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1760 CONVERT_CHECKED(String, source, args[1]);
1761
1762 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001764
1765 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001767
1768 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001770
1771 Map* map = regexp->map();
1772 Object* constructor = map->constructor();
1773 if (constructor->IsJSFunction() &&
1774 JSFunction::cast(constructor)->initial_map() == map) {
1775 // If we still have the original map, set in-object properties directly.
1776 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001777 // Both true and false are immovable immortal objects so no need for write
1778 // barrier.
1779 regexp->InObjectPropertyAtPut(
1780 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1781 regexp->InObjectPropertyAtPut(
1782 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1783 regexp->InObjectPropertyAtPut(
1784 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001785 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1786 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001787 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001788 return regexp;
1789 }
1790
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001791 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001792 PropertyAttributes final =
1793 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1794 PropertyAttributes writable =
1795 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001796 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001797 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001799 source,
1800 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001801 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001802 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001803 global,
1804 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001805 ASSERT(!result->IsFailure());
1806 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001807 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001808 ignoreCase,
1809 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001810 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001812 multiline,
1813 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001814 ASSERT(!result->IsFailure());
1815 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001817 Smi::FromInt(0),
1818 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001819 ASSERT(!result->IsFailure());
1820 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001821 return regexp;
1822}
1823
1824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001825RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001827 ASSERT(args.length() == 1);
1828 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1829 // This is necessary to enable fast checks for absence of elements
1830 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001832 return Smi::FromInt(0);
1833}
1834
1835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1837 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001838 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001839 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1841 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1842 Handle<JSFunction> optimized =
1843 isolate->factory()->NewFunction(key,
1844 JS_OBJECT_TYPE,
1845 JSObject::kHeaderSize,
1846 code,
1847 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001848 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001849 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001850 return optimized;
1851}
1852
1853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001854RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001856 ASSERT(args.length() == 1);
1857 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1858
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001859 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1860 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1861 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1862 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1863 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1864 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1865 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001866
1867 return *holder;
1868}
1869
1870
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001871RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1872 NoHandleAllocation handle_free;
1873 ASSERT(args.length() == 1);
1874 CONVERT_CHECKED(JSFunction, function, args[0]);
1875 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001876 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001877 return isolate->heap()->undefined_value();
1878 }
1879 // Returns undefined for strict or native functions, or
1880 // the associated global receiver for "normal" functions.
1881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001882 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001883 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001884 return global_context->global()->global_receiver();
1885}
1886
1887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001888RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 ASSERT(args.length() == 4);
1891 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001892 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001893 Handle<String> pattern = args.at<String>(2);
1894 Handle<String> flags = args.at<String>(3);
1895
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001896 // Get the RegExp function from the context in the literals array.
1897 // This is the RegExp function from the context in which the
1898 // function was created. We do not use the RegExp function from the
1899 // current global context because this might be the RegExp function
1900 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001901 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001902 Handle<JSFunction>(
1903 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904 // Compute the regular expression literal.
1905 bool has_pending_exception;
1906 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001907 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1908 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001909 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001910 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911 return Failure::Exception();
1912 }
1913 literals->set(index, *regexp);
1914 return *regexp;
1915}
1916
1917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001918RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 NoHandleAllocation ha;
1920 ASSERT(args.length() == 1);
1921
1922 CONVERT_CHECKED(JSFunction, f, args[0]);
1923 return f->shared()->name();
1924}
1925
1926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001927RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001928 NoHandleAllocation ha;
1929 ASSERT(args.length() == 2);
1930
1931 CONVERT_CHECKED(JSFunction, f, args[0]);
1932 CONVERT_CHECKED(String, name, args[1]);
1933 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001934 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001935}
1936
1937
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001938RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1939 NoHandleAllocation ha;
1940 ASSERT(args.length() == 1);
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
1942 return isolate->heap()->ToBoolean(
1943 f->shared()->name_should_print_as_anonymous());
1944}
1945
1946
1947RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1948 NoHandleAllocation ha;
1949 ASSERT(args.length() == 1);
1950 CONVERT_CHECKED(JSFunction, f, args[0]);
1951 f->shared()->set_name_should_print_as_anonymous(true);
1952 return isolate->heap()->undefined_value();
1953}
1954
1955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001956RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001957 NoHandleAllocation ha;
1958 ASSERT(args.length() == 1);
1959
1960 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001961 Object* obj = f->RemovePrototype();
1962 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001963
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001964 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001965}
1966
1967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001968RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001969 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001970 ASSERT(args.length() == 1);
1971
1972 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001973 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1974 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001975
1976 return *GetScriptWrapper(Handle<Script>::cast(script));
1977}
1978
1979
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001980RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001981 NoHandleAllocation ha;
1982 ASSERT(args.length() == 1);
1983
1984 CONVERT_CHECKED(JSFunction, f, args[0]);
1985 return f->shared()->GetSourceCode();
1986}
1987
1988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001989RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001990 NoHandleAllocation ha;
1991 ASSERT(args.length() == 1);
1992
1993 CONVERT_CHECKED(JSFunction, fun, args[0]);
1994 int pos = fun->shared()->start_position();
1995 return Smi::FromInt(pos);
1996}
1997
1998
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001999RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002000 ASSERT(args.length() == 2);
2001
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002002 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002003 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2004
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002005 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2006
2007 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002008 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002009}
2010
2011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002012RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 NoHandleAllocation ha;
2014 ASSERT(args.length() == 2);
2015
2016 CONVERT_CHECKED(JSFunction, fun, args[0]);
2017 CONVERT_CHECKED(String, name, args[1]);
2018 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002019 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002020}
2021
2022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002023RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002024 NoHandleAllocation ha;
2025 ASSERT(args.length() == 2);
2026
2027 CONVERT_CHECKED(JSFunction, fun, args[0]);
2028 CONVERT_CHECKED(Smi, length, args[1]);
2029 fun->shared()->set_length(length->value());
2030 return length;
2031}
2032
2033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002034RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002035 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036 ASSERT(args.length() == 2);
2037
2038 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002039 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002040 Object* obj;
2041 { MaybeObject* maybe_obj =
2042 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2043 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2044 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002045 return args[0]; // return TOS
2046}
2047
2048
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002049RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2050 NoHandleAllocation ha;
2051 RUNTIME_ASSERT(args.length() == 1);
2052 CONVERT_CHECKED(JSFunction, function, args[0]);
2053
2054 MaybeObject* maybe_name =
2055 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2056 String* name;
2057 if (!maybe_name->To(&name)) return maybe_name;
2058
2059 if (function->HasFastProperties()) {
2060 // Construct a new field descriptor with updated attributes.
2061 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2062 int index = instance_desc->Search(name);
2063 ASSERT(index != DescriptorArray::kNotFound);
2064 PropertyDetails details(instance_desc->GetDetails(index));
2065 CallbacksDescriptor new_desc(name,
2066 instance_desc->GetValue(index),
2067 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2068 details.index());
2069 // Construct a new field descriptors array containing the new descriptor.
2070 Object* descriptors_unchecked;
2071 { MaybeObject* maybe_descriptors_unchecked =
2072 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2073 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2074 return maybe_descriptors_unchecked;
2075 }
2076 }
2077 DescriptorArray* new_descriptors =
2078 DescriptorArray::cast(descriptors_unchecked);
2079 // Create a new map featuring the new field descriptors array.
2080 Object* map_unchecked;
2081 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2082 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2083 return maybe_map_unchecked;
2084 }
2085 }
2086 Map* new_map = Map::cast(map_unchecked);
2087 new_map->set_instance_descriptors(new_descriptors);
2088 function->set_map(new_map);
2089 } else { // Dictionary properties.
2090 // Directly manipulate the property details.
2091 int entry = function->property_dictionary()->FindEntry(name);
2092 ASSERT(entry != StringDictionary::kNotFound);
2093 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2094 PropertyDetails new_details(
2095 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2096 details.type(),
2097 details.index());
2098 function->property_dictionary()->DetailsAtPut(entry, new_details);
2099 }
2100 return function;
2101}
2102
2103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002104RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002105 NoHandleAllocation ha;
2106 ASSERT(args.length() == 1);
2107
2108 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002109 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002110}
2111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002113RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002114 NoHandleAllocation ha;
2115 ASSERT(args.length() == 1);
2116
2117 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002118 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002119}
2120
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002122RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002123 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002124 ASSERT(args.length() == 2);
2125
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002126 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002127 Handle<Object> code = args.at<Object>(1);
2128
2129 Handle<Context> context(target->context());
2130
2131 if (!code->IsNull()) {
2132 RUNTIME_ASSERT(code->IsJSFunction());
2133 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002134 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002135
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002136 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002137 return Failure::Exception();
2138 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002139 // Since we don't store the source for this we should never
2140 // optimize this.
2141 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002142 // Set the code, scope info, formal parameter count,
2143 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002144 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002145 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002146 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002147 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002148 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002149 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002150 // Set the source code of the target function to undefined.
2151 // SetCode is only used for built-in constructors like String,
2152 // Array, and Object, and some web code
2153 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002154 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002155 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002156 // Clear the optimization hints related to the compiled code as these are no
2157 // longer valid when the code is overwritten.
2158 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002159 context = Handle<Context>(fun->context());
2160
2161 // Make sure we get a fresh copy of the literal vector to avoid
2162 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002163 int number_of_literals = fun->NumberOfLiterals();
2164 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002165 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002166 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002167 // Insert the object, regexp and array functions in the literals
2168 // array prefix. These are the functions that will be used when
2169 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002170 literals->set(JSFunction::kLiteralGlobalContextIndex,
2171 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002173 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002174 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002175
2176 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2177 isolate->logger()->LogExistingFunction(
2178 shared, Handle<Code>(shared->code()));
2179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002180 }
2181
2182 target->set_context(*context);
2183 return *target;
2184}
2185
2186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002187RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002188 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002189 ASSERT(args.length() == 2);
2190 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002191 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002192 RUNTIME_ASSERT(num >= 0);
2193 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002195}
2196
2197
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002198MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2199 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002200 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002201 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002202 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002203 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002204 }
2205 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002206 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002207}
2208
2209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002210RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002211 NoHandleAllocation ha;
2212 ASSERT(args.length() == 2);
2213
2214 CONVERT_CHECKED(String, subject, args[0]);
2215 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002216 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002217
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002218 uint32_t i = 0;
2219 if (index->IsSmi()) {
2220 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002221 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002222 i = value;
2223 } else {
2224 ASSERT(index->IsHeapNumber());
2225 double value = HeapNumber::cast(index)->value();
2226 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002227 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002228
2229 // Flatten the string. If someone wants to get a char at an index
2230 // in a cons string, it is likely that more indices will be
2231 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002232 Object* flat;
2233 { MaybeObject* maybe_flat = subject->TryFlatten();
2234 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2235 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002236 subject = String::cast(flat);
2237
2238 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002239 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002240 }
2241
2242 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002243}
2244
2245
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002246RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002247 NoHandleAllocation ha;
2248 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002249 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002250}
2251
lrn@chromium.org25156de2010-04-06 13:10:27 +00002252
2253class FixedArrayBuilder {
2254 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002255 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2256 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002257 length_(0),
2258 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002259 // Require a non-zero initial size. Ensures that doubling the size to
2260 // extend the array will work.
2261 ASSERT(initial_capacity > 0);
2262 }
2263
2264 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2265 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002266 length_(0),
2267 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002268 // Require a non-zero initial size. Ensures that doubling the size to
2269 // extend the array will work.
2270 ASSERT(backing_store->length() > 0);
2271 }
2272
2273 bool HasCapacity(int elements) {
2274 int length = array_->length();
2275 int required_length = length_ + elements;
2276 return (length >= required_length);
2277 }
2278
2279 void EnsureCapacity(int elements) {
2280 int length = array_->length();
2281 int required_length = length_ + elements;
2282 if (length < required_length) {
2283 int new_length = length;
2284 do {
2285 new_length *= 2;
2286 } while (new_length < required_length);
2287 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002288 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002289 array_->CopyTo(0, *extended_array, 0, length_);
2290 array_ = extended_array;
2291 }
2292 }
2293
2294 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002295 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002296 ASSERT(length_ < capacity());
2297 array_->set(length_, value);
2298 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002299 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002300 }
2301
2302 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002303 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002304 ASSERT(length_ < capacity());
2305 array_->set(length_, value);
2306 length_++;
2307 }
2308
2309 Handle<FixedArray> array() {
2310 return array_;
2311 }
2312
2313 int length() {
2314 return length_;
2315 }
2316
2317 int capacity() {
2318 return array_->length();
2319 }
2320
2321 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002322 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002323 result_array->set_length(Smi::FromInt(length_));
2324 return result_array;
2325 }
2326
2327 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002328 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 target_array->set_length(Smi::FromInt(length_));
2330 return target_array;
2331 }
2332
2333 private:
2334 Handle<FixedArray> array_;
2335 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002336 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002337};
2338
2339
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002340// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002341const int kStringBuilderConcatHelperLengthBits = 11;
2342const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002343
2344template <typename schar>
2345static inline void StringBuilderConcatHelper(String*,
2346 schar*,
2347 FixedArray*,
2348 int);
2349
lrn@chromium.org25156de2010-04-06 13:10:27 +00002350typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2351 StringBuilderSubstringLength;
2352typedef BitField<int,
2353 kStringBuilderConcatHelperLengthBits,
2354 kStringBuilderConcatHelperPositionBits>
2355 StringBuilderSubstringPosition;
2356
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002357
2358class ReplacementStringBuilder {
2359 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002360 ReplacementStringBuilder(Heap* heap,
2361 Handle<String> subject,
2362 int estimated_part_count)
2363 : heap_(heap),
2364 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002365 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002366 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002367 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002368 // Require a non-zero initial size. Ensures that doubling the size to
2369 // extend the array will work.
2370 ASSERT(estimated_part_count > 0);
2371 }
2372
lrn@chromium.org25156de2010-04-06 13:10:27 +00002373 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2374 int from,
2375 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002376 ASSERT(from >= 0);
2377 int length = to - from;
2378 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002379 if (StringBuilderSubstringLength::is_valid(length) &&
2380 StringBuilderSubstringPosition::is_valid(from)) {
2381 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2382 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002383 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002384 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002385 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002386 builder->Add(Smi::FromInt(-length));
2387 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002389 }
2390
2391
2392 void EnsureCapacity(int elements) {
2393 array_builder_.EnsureCapacity(elements);
2394 }
2395
2396
2397 void AddSubjectSlice(int from, int to) {
2398 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002399 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002400 }
2401
2402
2403 void AddString(Handle<String> string) {
2404 int length = string->length();
2405 ASSERT(length > 0);
2406 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002407 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002408 is_ascii_ = false;
2409 }
2410 IncrementCharacterCount(length);
2411 }
2412
2413
2414 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002415 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002416 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002417 }
2418
2419 Handle<String> joined_string;
2420 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002421 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002422 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002423 char* char_buffer = seq->GetChars();
2424 StringBuilderConcatHelper(*subject_,
2425 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002426 *array_builder_.array(),
2427 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002428 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002429 } else {
2430 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002431 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002432 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002433 uc16* char_buffer = seq->GetChars();
2434 StringBuilderConcatHelper(*subject_,
2435 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002436 *array_builder_.array(),
2437 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002438 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 }
2440 return joined_string;
2441 }
2442
2443
2444 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002445 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002446 V8::FatalProcessOutOfMemory("String.replace result too large.");
2447 }
2448 character_count_ += by;
2449 }
2450
lrn@chromium.org25156de2010-04-06 13:10:27 +00002451 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002452 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002453 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002454
lrn@chromium.org25156de2010-04-06 13:10:27 +00002455 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002456 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2457 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002458 }
2459
2460
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2462 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 }
2464
2465
2466 void AddElement(Object* element) {
2467 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002468 ASSERT(array_builder_.capacity() > array_builder_.length());
2469 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002470 }
2471
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002472 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002473 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002474 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002475 int character_count_;
2476 bool is_ascii_;
2477};
2478
2479
2480class CompiledReplacement {
2481 public:
2482 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002483 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002484
2485 void Compile(Handle<String> replacement,
2486 int capture_count,
2487 int subject_length);
2488
2489 void Apply(ReplacementStringBuilder* builder,
2490 int match_from,
2491 int match_to,
2492 Handle<JSArray> last_match_info);
2493
2494 // Number of distinct parts of the replacement pattern.
2495 int parts() {
2496 return parts_.length();
2497 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002498
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002499 bool simple_hint() {
2500 return simple_hint_;
2501 }
2502
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002503 private:
2504 enum PartType {
2505 SUBJECT_PREFIX = 1,
2506 SUBJECT_SUFFIX,
2507 SUBJECT_CAPTURE,
2508 REPLACEMENT_SUBSTRING,
2509 REPLACEMENT_STRING,
2510
2511 NUMBER_OF_PART_TYPES
2512 };
2513
2514 struct ReplacementPart {
2515 static inline ReplacementPart SubjectMatch() {
2516 return ReplacementPart(SUBJECT_CAPTURE, 0);
2517 }
2518 static inline ReplacementPart SubjectCapture(int capture_index) {
2519 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2520 }
2521 static inline ReplacementPart SubjectPrefix() {
2522 return ReplacementPart(SUBJECT_PREFIX, 0);
2523 }
2524 static inline ReplacementPart SubjectSuffix(int subject_length) {
2525 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2526 }
2527 static inline ReplacementPart ReplacementString() {
2528 return ReplacementPart(REPLACEMENT_STRING, 0);
2529 }
2530 static inline ReplacementPart ReplacementSubString(int from, int to) {
2531 ASSERT(from >= 0);
2532 ASSERT(to > from);
2533 return ReplacementPart(-from, to);
2534 }
2535
2536 // If tag <= 0 then it is the negation of a start index of a substring of
2537 // the replacement pattern, otherwise it's a value from PartType.
2538 ReplacementPart(int tag, int data)
2539 : tag(tag), data(data) {
2540 // Must be non-positive or a PartType value.
2541 ASSERT(tag < NUMBER_OF_PART_TYPES);
2542 }
2543 // Either a value of PartType or a non-positive number that is
2544 // the negation of an index into the replacement string.
2545 int tag;
2546 // The data value's interpretation depends on the value of tag:
2547 // tag == SUBJECT_PREFIX ||
2548 // tag == SUBJECT_SUFFIX: data is unused.
2549 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2550 // tag == REPLACEMENT_SUBSTRING ||
2551 // tag == REPLACEMENT_STRING: data is index into array of substrings
2552 // of the replacement string.
2553 // tag <= 0: Temporary representation of the substring of the replacement
2554 // string ranging over -tag .. data.
2555 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2556 // substring objects.
2557 int data;
2558 };
2559
2560 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002561 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002562 Vector<Char> characters,
2563 int capture_count,
2564 int subject_length) {
2565 int length = characters.length();
2566 int last = 0;
2567 for (int i = 0; i < length; i++) {
2568 Char c = characters[i];
2569 if (c == '$') {
2570 int next_index = i + 1;
2571 if (next_index == length) { // No next character!
2572 break;
2573 }
2574 Char c2 = characters[next_index];
2575 switch (c2) {
2576 case '$':
2577 if (i > last) {
2578 // There is a substring before. Include the first "$".
2579 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2580 last = next_index + 1; // Continue after the second "$".
2581 } else {
2582 // Let the next substring start with the second "$".
2583 last = next_index;
2584 }
2585 i = next_index;
2586 break;
2587 case '`':
2588 if (i > last) {
2589 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2590 }
2591 parts->Add(ReplacementPart::SubjectPrefix());
2592 i = next_index;
2593 last = i + 1;
2594 break;
2595 case '\'':
2596 if (i > last) {
2597 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2598 }
2599 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2600 i = next_index;
2601 last = i + 1;
2602 break;
2603 case '&':
2604 if (i > last) {
2605 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2606 }
2607 parts->Add(ReplacementPart::SubjectMatch());
2608 i = next_index;
2609 last = i + 1;
2610 break;
2611 case '0':
2612 case '1':
2613 case '2':
2614 case '3':
2615 case '4':
2616 case '5':
2617 case '6':
2618 case '7':
2619 case '8':
2620 case '9': {
2621 int capture_ref = c2 - '0';
2622 if (capture_ref > capture_count) {
2623 i = next_index;
2624 continue;
2625 }
2626 int second_digit_index = next_index + 1;
2627 if (second_digit_index < length) {
2628 // Peek ahead to see if we have two digits.
2629 Char c3 = characters[second_digit_index];
2630 if ('0' <= c3 && c3 <= '9') { // Double digits.
2631 int double_digit_ref = capture_ref * 10 + c3 - '0';
2632 if (double_digit_ref <= capture_count) {
2633 next_index = second_digit_index;
2634 capture_ref = double_digit_ref;
2635 }
2636 }
2637 }
2638 if (capture_ref > 0) {
2639 if (i > last) {
2640 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2641 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002642 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002643 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2644 last = next_index + 1;
2645 }
2646 i = next_index;
2647 break;
2648 }
2649 default:
2650 i = next_index;
2651 break;
2652 }
2653 }
2654 }
2655 if (length > last) {
2656 if (last == 0) {
2657 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002658 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002659 } else {
2660 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2661 }
2662 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002663 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002664 }
2665
2666 ZoneList<ReplacementPart> parts_;
2667 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002668 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002669};
2670
2671
2672void CompiledReplacement::Compile(Handle<String> replacement,
2673 int capture_count,
2674 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002675 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002676 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002677 String::FlatContent content = replacement->GetFlatContent();
2678 ASSERT(content.IsFlat());
2679 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002680 simple_hint_ = ParseReplacementPattern(&parts_,
2681 content.ToAsciiVector(),
2682 capture_count,
2683 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002684 } else {
2685 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002686 simple_hint_ = ParseReplacementPattern(&parts_,
2687 content.ToUC16Vector(),
2688 capture_count,
2689 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002690 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002691 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002692 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002693 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002694 int substring_index = 0;
2695 for (int i = 0, n = parts_.length(); i < n; i++) {
2696 int tag = parts_[i].tag;
2697 if (tag <= 0) { // A replacement string slice.
2698 int from = -tag;
2699 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002700 replacement_substrings_.Add(
2701 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002702 parts_[i].tag = REPLACEMENT_SUBSTRING;
2703 parts_[i].data = substring_index;
2704 substring_index++;
2705 } else if (tag == REPLACEMENT_STRING) {
2706 replacement_substrings_.Add(replacement);
2707 parts_[i].data = substring_index;
2708 substring_index++;
2709 }
2710 }
2711}
2712
2713
2714void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2715 int match_from,
2716 int match_to,
2717 Handle<JSArray> last_match_info) {
2718 for (int i = 0, n = parts_.length(); i < n; i++) {
2719 ReplacementPart part = parts_[i];
2720 switch (part.tag) {
2721 case SUBJECT_PREFIX:
2722 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2723 break;
2724 case SUBJECT_SUFFIX: {
2725 int subject_length = part.data;
2726 if (match_to < subject_length) {
2727 builder->AddSubjectSlice(match_to, subject_length);
2728 }
2729 break;
2730 }
2731 case SUBJECT_CAPTURE: {
2732 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002733 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002734 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2735 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2736 if (from >= 0 && to > from) {
2737 builder->AddSubjectSlice(from, to);
2738 }
2739 break;
2740 }
2741 case REPLACEMENT_SUBSTRING:
2742 case REPLACEMENT_STRING:
2743 builder->AddString(replacement_substrings_[part.data]);
2744 break;
2745 default:
2746 UNREACHABLE();
2747 }
2748 }
2749}
2750
2751
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002752void FindAsciiStringIndices(Vector<const char> subject,
2753 char pattern,
2754 ZoneList<int>* indices,
2755 unsigned int limit) {
2756 ASSERT(limit > 0);
2757 // Collect indices of pattern in subject using memchr.
2758 // Stop after finding at most limit values.
2759 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2760 const char* subject_end = subject_start + subject.length();
2761 const char* pos = subject_start;
2762 while (limit > 0) {
2763 pos = reinterpret_cast<const char*>(
2764 memchr(pos, pattern, subject_end - pos));
2765 if (pos == NULL) return;
2766 indices->Add(static_cast<int>(pos - subject_start));
2767 pos++;
2768 limit--;
2769 }
2770}
2771
2772
2773template <typename SubjectChar, typename PatternChar>
2774void FindStringIndices(Isolate* isolate,
2775 Vector<const SubjectChar> subject,
2776 Vector<const PatternChar> pattern,
2777 ZoneList<int>* indices,
2778 unsigned int limit) {
2779 ASSERT(limit > 0);
2780 // Collect indices of pattern in subject.
2781 // Stop after finding at most limit values.
2782 int pattern_length = pattern.length();
2783 int index = 0;
2784 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2785 while (limit > 0) {
2786 index = search.Search(subject, index);
2787 if (index < 0) return;
2788 indices->Add(index);
2789 index += pattern_length;
2790 limit--;
2791 }
2792}
2793
2794
2795void FindStringIndicesDispatch(Isolate* isolate,
2796 String* subject,
2797 String* pattern,
2798 ZoneList<int>* indices,
2799 unsigned int limit) {
2800 {
2801 AssertNoAllocation no_gc;
2802 String::FlatContent subject_content = subject->GetFlatContent();
2803 String::FlatContent pattern_content = pattern->GetFlatContent();
2804 ASSERT(subject_content.IsFlat());
2805 ASSERT(pattern_content.IsFlat());
2806 if (subject_content.IsAscii()) {
2807 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2808 if (pattern_content.IsAscii()) {
2809 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2810 if (pattern_vector.length() == 1) {
2811 FindAsciiStringIndices(subject_vector,
2812 pattern_vector[0],
2813 indices,
2814 limit);
2815 } else {
2816 FindStringIndices(isolate,
2817 subject_vector,
2818 pattern_vector,
2819 indices,
2820 limit);
2821 }
2822 } else {
2823 FindStringIndices(isolate,
2824 subject_vector,
2825 pattern_content.ToUC16Vector(),
2826 indices,
2827 limit);
2828 }
2829 } else {
2830 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002831 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002832 FindStringIndices(isolate,
2833 subject_vector,
2834 pattern_content.ToAsciiVector(),
2835 indices,
2836 limit);
2837 } else {
2838 FindStringIndices(isolate,
2839 subject_vector,
2840 pattern_content.ToUC16Vector(),
2841 indices,
2842 limit);
2843 }
2844 }
2845 }
2846}
2847
2848
2849template<typename ResultSeqString>
2850MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2851 Isolate* isolate,
2852 Handle<String> subject,
2853 Handle<JSRegExp> pattern_regexp,
2854 Handle<String> replacement) {
2855 ASSERT(subject->IsFlat());
2856 ASSERT(replacement->IsFlat());
2857
2858 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2859 ZoneList<int> indices(8);
2860 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2861 String* pattern =
2862 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2863 int subject_len = subject->length();
2864 int pattern_len = pattern->length();
2865 int replacement_len = replacement->length();
2866
2867 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2868
2869 int matches = indices.length();
2870 if (matches == 0) return *subject;
2871
2872 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2873 int subject_pos = 0;
2874 int result_pos = 0;
2875
2876 Handle<ResultSeqString> result;
2877 if (ResultSeqString::kHasAsciiEncoding) {
2878 result = Handle<ResultSeqString>::cast(
2879 isolate->factory()->NewRawAsciiString(result_len));
2880 } else {
2881 result = Handle<ResultSeqString>::cast(
2882 isolate->factory()->NewRawTwoByteString(result_len));
2883 }
2884
2885 for (int i = 0; i < matches; i++) {
2886 // Copy non-matched subject content.
2887 if (subject_pos < indices.at(i)) {
2888 String::WriteToFlat(*subject,
2889 result->GetChars() + result_pos,
2890 subject_pos,
2891 indices.at(i));
2892 result_pos += indices.at(i) - subject_pos;
2893 }
2894
2895 // Replace match.
2896 if (replacement_len > 0) {
2897 String::WriteToFlat(*replacement,
2898 result->GetChars() + result_pos,
2899 0,
2900 replacement_len);
2901 result_pos += replacement_len;
2902 }
2903
2904 subject_pos = indices.at(i) + pattern_len;
2905 }
2906 // Add remaining subject content at the end.
2907 if (subject_pos < subject_len) {
2908 String::WriteToFlat(*subject,
2909 result->GetChars() + result_pos,
2910 subject_pos,
2911 subject_len);
2912 }
2913 return *result;
2914}
2915
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002916
lrn@chromium.org303ada72010-10-27 09:33:13 +00002917MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002918 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002919 String* subject,
2920 JSRegExp* regexp,
2921 String* replacement,
2922 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002923 ASSERT(subject->IsFlat());
2924 ASSERT(replacement->IsFlat());
2925
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002926 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002927
2928 int length = subject->length();
2929 Handle<String> subject_handle(subject);
2930 Handle<JSRegExp> regexp_handle(regexp);
2931 Handle<String> replacement_handle(replacement);
2932 Handle<JSArray> last_match_info_handle(last_match_info);
2933 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2934 subject_handle,
2935 0,
2936 last_match_info_handle);
2937 if (match.is_null()) {
2938 return Failure::Exception();
2939 }
2940 if (match->IsNull()) {
2941 return *subject_handle;
2942 }
2943
2944 int capture_count = regexp_handle->CaptureCount();
2945
2946 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002947 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002948 CompiledReplacement compiled_replacement;
2949 compiled_replacement.Compile(replacement_handle,
2950 capture_count,
2951 length);
2952
2953 bool is_global = regexp_handle->GetFlags().is_global();
2954
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002955 // Shortcut for simple non-regexp global replacements
2956 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002957 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002958 compiled_replacement.simple_hint()) {
2959 if (subject_handle->HasOnlyAsciiChars() &&
2960 replacement_handle->HasOnlyAsciiChars()) {
2961 return StringReplaceStringWithString<SeqAsciiString>(
2962 isolate, subject_handle, regexp_handle, replacement_handle);
2963 } else {
2964 return StringReplaceStringWithString<SeqTwoByteString>(
2965 isolate, subject_handle, regexp_handle, replacement_handle);
2966 }
2967 }
2968
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002969 // Guessing the number of parts that the final result string is built
2970 // from. Global regexps can match any number of times, so we guess
2971 // conservatively.
2972 int expected_parts =
2973 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002974 ReplacementStringBuilder builder(isolate->heap(),
2975 subject_handle,
2976 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002977
2978 // Index of end of last match.
2979 int prev = 0;
2980
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002981 // Number of parts added by compiled replacement plus preceeding
2982 // string and possibly suffix after last match. It is possible for
2983 // all components to use two elements when encoded as two smis.
2984 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002985 bool matched = true;
2986 do {
2987 ASSERT(last_match_info_handle->HasFastElements());
2988 // Increase the capacity of the builder before entering local handle-scope,
2989 // so its internal buffer can safely allocate a new handle if it grows.
2990 builder.EnsureCapacity(parts_added_per_loop);
2991
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002992 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002993 int start, end;
2994 {
2995 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002996 FixedArray* match_info_array =
2997 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002998
2999 ASSERT_EQ(capture_count * 2 + 2,
3000 RegExpImpl::GetLastCaptureCount(match_info_array));
3001 start = RegExpImpl::GetCapture(match_info_array, 0);
3002 end = RegExpImpl::GetCapture(match_info_array, 1);
3003 }
3004
3005 if (prev < start) {
3006 builder.AddSubjectSlice(prev, start);
3007 }
3008 compiled_replacement.Apply(&builder,
3009 start,
3010 end,
3011 last_match_info_handle);
3012 prev = end;
3013
3014 // Only continue checking for global regexps.
3015 if (!is_global) break;
3016
3017 // Continue from where the match ended, unless it was an empty match.
3018 int next = end;
3019 if (start == end) {
3020 next = end + 1;
3021 if (next > length) break;
3022 }
3023
3024 match = RegExpImpl::Exec(regexp_handle,
3025 subject_handle,
3026 next,
3027 last_match_info_handle);
3028 if (match.is_null()) {
3029 return Failure::Exception();
3030 }
3031 matched = !match->IsNull();
3032 } while (matched);
3033
3034 if (prev < length) {
3035 builder.AddSubjectSlice(prev, length);
3036 }
3037
3038 return *(builder.ToString());
3039}
3040
3041
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003042template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003043MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003044 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003045 String* subject,
3046 JSRegExp* regexp,
3047 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003048 ASSERT(subject->IsFlat());
3049
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003050 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003051
3052 Handle<String> subject_handle(subject);
3053 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003054
3055 // Shortcut for simple non-regexp global replacements
3056 if (regexp_handle->GetFlags().is_global() &&
3057 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3058 Handle<String> empty_string_handle(HEAP->empty_string());
3059 if (subject_handle->HasOnlyAsciiChars()) {
3060 return StringReplaceStringWithString<SeqAsciiString>(
3061 isolate, subject_handle, regexp_handle, empty_string_handle);
3062 } else {
3063 return StringReplaceStringWithString<SeqTwoByteString>(
3064 isolate, subject_handle, regexp_handle, empty_string_handle);
3065 }
3066 }
3067
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003068 Handle<JSArray> last_match_info_handle(last_match_info);
3069 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3070 subject_handle,
3071 0,
3072 last_match_info_handle);
3073 if (match.is_null()) return Failure::Exception();
3074 if (match->IsNull()) return *subject_handle;
3075
3076 ASSERT(last_match_info_handle->HasFastElements());
3077
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003078 int start, end;
3079 {
3080 AssertNoAllocation match_info_array_is_not_in_a_handle;
3081 FixedArray* match_info_array =
3082 FixedArray::cast(last_match_info_handle->elements());
3083
3084 start = RegExpImpl::GetCapture(match_info_array, 0);
3085 end = RegExpImpl::GetCapture(match_info_array, 1);
3086 }
3087
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003088 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003089 int new_length = length - (end - start);
3090 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003091 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003092 }
3093 Handle<ResultSeqString> answer;
3094 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003095 answer = Handle<ResultSeqString>::cast(
3096 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003097 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003098 answer = Handle<ResultSeqString>::cast(
3099 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003100 }
3101
3102 // If the regexp isn't global, only match once.
3103 if (!regexp_handle->GetFlags().is_global()) {
3104 if (start > 0) {
3105 String::WriteToFlat(*subject_handle,
3106 answer->GetChars(),
3107 0,
3108 start);
3109 }
3110 if (end < length) {
3111 String::WriteToFlat(*subject_handle,
3112 answer->GetChars() + start,
3113 end,
3114 length);
3115 }
3116 return *answer;
3117 }
3118
3119 int prev = 0; // Index of end of last match.
3120 int next = 0; // Start of next search (prev unless last match was empty).
3121 int position = 0;
3122
3123 do {
3124 if (prev < start) {
3125 // Add substring subject[prev;start] to answer string.
3126 String::WriteToFlat(*subject_handle,
3127 answer->GetChars() + position,
3128 prev,
3129 start);
3130 position += start - prev;
3131 }
3132 prev = end;
3133 next = end;
3134 // Continue from where the match ended, unless it was an empty match.
3135 if (start == end) {
3136 next++;
3137 if (next > length) break;
3138 }
3139 match = RegExpImpl::Exec(regexp_handle,
3140 subject_handle,
3141 next,
3142 last_match_info_handle);
3143 if (match.is_null()) return Failure::Exception();
3144 if (match->IsNull()) break;
3145
3146 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003147 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003148 {
3149 AssertNoAllocation match_info_array_is_not_in_a_handle;
3150 FixedArray* match_info_array =
3151 FixedArray::cast(last_match_info_handle->elements());
3152 start = RegExpImpl::GetCapture(match_info_array, 0);
3153 end = RegExpImpl::GetCapture(match_info_array, 1);
3154 }
3155 } while (true);
3156
3157 if (prev < length) {
3158 // Add substring subject[prev;length] to answer string.
3159 String::WriteToFlat(*subject_handle,
3160 answer->GetChars() + position,
3161 prev,
3162 length);
3163 position += length - prev;
3164 }
3165
3166 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003167 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003168 }
3169
3170 // Shorten string and fill
3171 int string_size = ResultSeqString::SizeFor(position);
3172 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3173 int delta = allocated_string_size - string_size;
3174
3175 answer->set_length(position);
3176 if (delta == 0) return *answer;
3177
3178 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003179 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003180 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003181 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003182 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003183
3184 return *answer;
3185}
3186
3187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003188RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003189 ASSERT(args.length() == 4);
3190
3191 CONVERT_CHECKED(String, subject, args[0]);
3192 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003193 Object* flat_subject;
3194 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3195 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3196 return maybe_flat_subject;
3197 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003198 }
3199 subject = String::cast(flat_subject);
3200 }
3201
3202 CONVERT_CHECKED(String, replacement, args[2]);
3203 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003204 Object* flat_replacement;
3205 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3206 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3207 return maybe_flat_replacement;
3208 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003209 }
3210 replacement = String::cast(flat_replacement);
3211 }
3212
3213 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3214 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3215
3216 ASSERT(last_match_info->HasFastElements());
3217
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003218 if (replacement->length() == 0) {
3219 if (subject->HasOnlyAsciiChars()) {
3220 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003221 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003222 } else {
3223 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003224 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003225 }
3226 }
3227
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003228 return StringReplaceRegExpWithString(isolate,
3229 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003230 regexp,
3231 replacement,
3232 last_match_info);
3233}
3234
3235
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003236Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3237 Handle<String> subject,
3238 Handle<String> search,
3239 Handle<String> replace,
3240 bool* found,
3241 int recursion_limit) {
3242 if (recursion_limit == 0) return Handle<String>::null();
3243 if (subject->IsConsString()) {
3244 ConsString* cons = ConsString::cast(*subject);
3245 Handle<String> first = Handle<String>(cons->first());
3246 Handle<String> second = Handle<String>(cons->second());
3247 Handle<String> new_first =
3248 StringReplaceOneCharWithString(isolate,
3249 first,
3250 search,
3251 replace,
3252 found,
3253 recursion_limit - 1);
3254 if (*found) return isolate->factory()->NewConsString(new_first, second);
3255 if (new_first.is_null()) return new_first;
3256
3257 Handle<String> new_second =
3258 StringReplaceOneCharWithString(isolate,
3259 second,
3260 search,
3261 replace,
3262 found,
3263 recursion_limit - 1);
3264 if (*found) return isolate->factory()->NewConsString(first, new_second);
3265 if (new_second.is_null()) return new_second;
3266
3267 return subject;
3268 } else {
3269 int index = StringMatch(isolate, subject, search, 0);
3270 if (index == -1) return subject;
3271 *found = true;
3272 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3273 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3274 Handle<String> second =
3275 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3276 return isolate->factory()->NewConsString(cons1, second);
3277 }
3278}
3279
3280
3281RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3282 ASSERT(args.length() == 3);
3283 HandleScope scope(isolate);
3284 CONVERT_ARG_CHECKED(String, subject, 0);
3285 CONVERT_ARG_CHECKED(String, search, 1);
3286 CONVERT_ARG_CHECKED(String, replace, 2);
3287
3288 // If the cons string tree is too deep, we simply abort the recursion and
3289 // retry with a flattened subject string.
3290 const int kRecursionLimit = 0x1000;
3291 bool found = false;
3292 Handle<String> result =
3293 Runtime::StringReplaceOneCharWithString(isolate,
3294 subject,
3295 search,
3296 replace,
3297 &found,
3298 kRecursionLimit);
3299 if (!result.is_null()) return *result;
3300 return *Runtime::StringReplaceOneCharWithString(isolate,
3301 FlattenGetString(subject),
3302 search,
3303 replace,
3304 &found,
3305 kRecursionLimit);
3306}
3307
3308
ager@chromium.org7c537e22008-10-16 08:43:32 +00003309// Perform string match of pattern on subject, starting at start index.
3310// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003311// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003312int Runtime::StringMatch(Isolate* isolate,
3313 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003314 Handle<String> pat,
3315 int start_index) {
3316 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003317 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003318
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003319 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003320 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003321
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003322 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003323 if (start_index + pattern_length > subject_length) return -1;
3324
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003325 if (!sub->IsFlat()) FlattenString(sub);
3326 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003327
ager@chromium.org7c537e22008-10-16 08:43:32 +00003328 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003329 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003330 String::FlatContent seq_sub = sub->GetFlatContent();
3331 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003332
ager@chromium.org7c537e22008-10-16 08:43:32 +00003333 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003334 if (seq_pat.IsAscii()) {
3335 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3336 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003337 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003338 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003339 pat_vector,
3340 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003341 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003342 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003343 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003344 pat_vector,
3345 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003346 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003347 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3348 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003349 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003350 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003351 pat_vector,
3352 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003354 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003355 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003356 pat_vector,
3357 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003358}
3359
3360
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003361RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003362 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003363 ASSERT(args.length() == 3);
3364
ager@chromium.org7c537e22008-10-16 08:43:32 +00003365 CONVERT_ARG_CHECKED(String, sub, 0);
3366 CONVERT_ARG_CHECKED(String, pat, 1);
3367
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003368 Object* index = args[2];
3369 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003370 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003371
ager@chromium.org870a0b62008-11-04 11:43:05 +00003372 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003373 int position =
3374 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003375 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003376}
3377
3378
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003379template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003380static int StringMatchBackwards(Vector<const schar> subject,
3381 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003382 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003383 int pattern_length = pattern.length();
3384 ASSERT(pattern_length >= 1);
3385 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003386
3387 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003388 for (int i = 0; i < pattern_length; i++) {
3389 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003390 if (c > String::kMaxAsciiCharCode) {
3391 return -1;
3392 }
3393 }
3394 }
3395
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003396 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003397 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003398 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003399 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003400 while (j < pattern_length) {
3401 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003402 break;
3403 }
3404 j++;
3405 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003406 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003407 return i;
3408 }
3409 }
3410 return -1;
3411}
3412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003413RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003414 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003415 ASSERT(args.length() == 3);
3416
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003417 CONVERT_ARG_CHECKED(String, sub, 0);
3418 CONVERT_ARG_CHECKED(String, pat, 1);
3419
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003420 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003421 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003422 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003423
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003424 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003425 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003426
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003427 if (start_index + pat_length > sub_length) {
3428 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003429 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003430
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003431 if (pat_length == 0) {
3432 return Smi::FromInt(start_index);
3433 }
3434
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003435 if (!sub->IsFlat()) FlattenString(sub);
3436 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003437
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003438 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003439 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3440
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003441 String::FlatContent sub_content = sub->GetFlatContent();
3442 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003443
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003444 if (pat_content.IsAscii()) {
3445 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3446 if (sub_content.IsAscii()) {
3447 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003448 pat_vector,
3449 start_index);
3450 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003451 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003452 pat_vector,
3453 start_index);
3454 }
3455 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003456 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3457 if (sub_content.IsAscii()) {
3458 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003459 pat_vector,
3460 start_index);
3461 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003462 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003463 pat_vector,
3464 start_index);
3465 }
3466 }
3467
3468 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003469}
3470
3471
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003472RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003473 NoHandleAllocation ha;
3474 ASSERT(args.length() == 2);
3475
3476 CONVERT_CHECKED(String, str1, args[0]);
3477 CONVERT_CHECKED(String, str2, args[1]);
3478
3479 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003480 int str1_length = str1->length();
3481 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003482
3483 // Decide trivial cases without flattening.
3484 if (str1_length == 0) {
3485 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3486 return Smi::FromInt(-str2_length);
3487 } else {
3488 if (str2_length == 0) return Smi::FromInt(str1_length);
3489 }
3490
3491 int end = str1_length < str2_length ? str1_length : str2_length;
3492
3493 // No need to flatten if we are going to find the answer on the first
3494 // character. At this point we know there is at least one character
3495 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003496 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003497 if (d != 0) return Smi::FromInt(d);
3498
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003499 str1->TryFlatten();
3500 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003501
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003502 StringInputBuffer& buf1 =
3503 *isolate->runtime_state()->string_locale_compare_buf1();
3504 StringInputBuffer& buf2 =
3505 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003506
3507 buf1.Reset(str1);
3508 buf2.Reset(str2);
3509
3510 for (int i = 0; i < end; i++) {
3511 uint16_t char1 = buf1.GetNext();
3512 uint16_t char2 = buf2.GetNext();
3513 if (char1 != char2) return Smi::FromInt(char1 - char2);
3514 }
3515
3516 return Smi::FromInt(str1_length - str2_length);
3517}
3518
3519
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003520RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521 NoHandleAllocation ha;
3522 ASSERT(args.length() == 3);
3523
3524 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003525 int start, end;
3526 // We have a fast integer-only case here to avoid a conversion to double in
3527 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003528 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3529 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3530 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3531 start = from_number;
3532 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003533 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003534 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3535 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003536 start = FastD2I(from_number);
3537 end = FastD2I(to_number);
3538 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003539 RUNTIME_ASSERT(end >= start);
3540 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003541 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003542 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003543 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003544}
3545
3546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003547RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003548 ASSERT_EQ(3, args.length());
3549
3550 CONVERT_ARG_CHECKED(String, subject, 0);
3551 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3552 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3553 HandleScope handles;
3554
3555 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3556
3557 if (match.is_null()) {
3558 return Failure::Exception();
3559 }
3560 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003561 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003562 }
3563 int length = subject->length();
3564
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003565 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003566 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003567 int start;
3568 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003569 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003570 {
3571 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003572 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003573 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3574 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3575 }
3576 offsets.Add(start);
3577 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003578 if (start == end) if (++end > length) break;
3579 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003580 if (match.is_null()) {
3581 return Failure::Exception();
3582 }
3583 } while (!match->IsNull());
3584 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003585 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003586 Handle<String> substring = isolate->factory()->
3587 NewSubString(subject, offsets.at(0), offsets.at(1));
3588 elements->set(0, *substring);
3589 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003590 int from = offsets.at(i * 2);
3591 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003592 Handle<String> substring = isolate->factory()->
3593 NewProperSubString(subject, from, to);
3594 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003595 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003596 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003597 result->set_length(Smi::FromInt(matches));
3598 return *result;
3599}
3600
3601
lrn@chromium.org25156de2010-04-06 13:10:27 +00003602// Two smis before and after the match, for very long strings.
3603const int kMaxBuilderEntriesPerRegExpMatch = 5;
3604
3605
3606static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3607 Handle<JSArray> last_match_info,
3608 int match_start,
3609 int match_end) {
3610 // Fill last_match_info with a single capture.
3611 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3612 AssertNoAllocation no_gc;
3613 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3614 RegExpImpl::SetLastCaptureCount(elements, 2);
3615 RegExpImpl::SetLastInput(elements, *subject);
3616 RegExpImpl::SetLastSubject(elements, *subject);
3617 RegExpImpl::SetCapture(elements, 0, match_start);
3618 RegExpImpl::SetCapture(elements, 1, match_end);
3619}
3620
3621
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003622template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003623static bool SearchStringMultiple(Isolate* isolate,
3624 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003625 Vector<const PatternChar> pattern,
3626 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003627 FixedArrayBuilder* builder,
3628 int* match_pos) {
3629 int pos = *match_pos;
3630 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003631 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003632 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003633 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003634 while (pos <= max_search_start) {
3635 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3636 *match_pos = pos;
3637 return false;
3638 }
3639 // Position of end of previous match.
3640 int match_end = pos + pattern_length;
3641 int new_pos = search.Search(subject, match_end);
3642 if (new_pos >= 0) {
3643 // A match.
3644 if (new_pos > match_end) {
3645 ReplacementStringBuilder::AddSubjectSlice(builder,
3646 match_end,
3647 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003648 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003649 pos = new_pos;
3650 builder->Add(pattern_string);
3651 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003652 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003653 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003654 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003655
lrn@chromium.org25156de2010-04-06 13:10:27 +00003656 if (pos < max_search_start) {
3657 ReplacementStringBuilder::AddSubjectSlice(builder,
3658 pos + pattern_length,
3659 subject_length);
3660 }
3661 *match_pos = pos;
3662 return true;
3663}
3664
3665
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003666static bool SearchStringMultiple(Isolate* isolate,
3667 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003668 Handle<String> pattern,
3669 Handle<JSArray> last_match_info,
3670 FixedArrayBuilder* builder) {
3671 ASSERT(subject->IsFlat());
3672 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003673
3674 // Treating as if a previous match was before first character.
3675 int match_pos = -pattern->length();
3676
3677 for (;;) { // Break when search complete.
3678 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3679 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003680 String::FlatContent subject_content = subject->GetFlatContent();
3681 String::FlatContent pattern_content = pattern->GetFlatContent();
3682 if (subject_content.IsAscii()) {
3683 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3684 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 if (SearchStringMultiple(isolate,
3686 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003687 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003688 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003689 builder,
3690 &match_pos)) break;
3691 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003692 if (SearchStringMultiple(isolate,
3693 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003694 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003695 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003696 builder,
3697 &match_pos)) break;
3698 }
3699 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003700 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3701 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003702 if (SearchStringMultiple(isolate,
3703 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003704 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003705 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003706 builder,
3707 &match_pos)) break;
3708 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003709 if (SearchStringMultiple(isolate,
3710 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003711 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003712 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003713 builder,
3714 &match_pos)) break;
3715 }
3716 }
3717 }
3718
3719 if (match_pos >= 0) {
3720 SetLastMatchInfoNoCaptures(subject,
3721 last_match_info,
3722 match_pos,
3723 match_pos + pattern->length());
3724 return true;
3725 }
3726 return false; // No matches at all.
3727}
3728
3729
3730static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003731 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003732 Handle<String> subject,
3733 Handle<JSRegExp> regexp,
3734 Handle<JSArray> last_match_array,
3735 FixedArrayBuilder* builder) {
3736 ASSERT(subject->IsFlat());
3737 int match_start = -1;
3738 int match_end = 0;
3739 int pos = 0;
3740 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3741 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3742
3743 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003744 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003745 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003746 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003747
3748 for (;;) { // Break on failure, return on exception.
3749 RegExpImpl::IrregexpResult result =
3750 RegExpImpl::IrregexpExecOnce(regexp,
3751 subject,
3752 pos,
3753 register_vector);
3754 if (result == RegExpImpl::RE_SUCCESS) {
3755 match_start = register_vector[0];
3756 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3757 if (match_end < match_start) {
3758 ReplacementStringBuilder::AddSubjectSlice(builder,
3759 match_end,
3760 match_start);
3761 }
3762 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003763 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003764 if (!first) {
3765 builder->Add(*isolate->factory()->NewProperSubString(subject,
3766 match_start,
3767 match_end));
3768 } else {
3769 builder->Add(*isolate->factory()->NewSubString(subject,
3770 match_start,
3771 match_end));
3772 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003773 if (match_start != match_end) {
3774 pos = match_end;
3775 } else {
3776 pos = match_end + 1;
3777 if (pos > subject_length) break;
3778 }
3779 } else if (result == RegExpImpl::RE_FAILURE) {
3780 break;
3781 } else {
3782 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3783 return result;
3784 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003785 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003786 }
3787
3788 if (match_start >= 0) {
3789 if (match_end < subject_length) {
3790 ReplacementStringBuilder::AddSubjectSlice(builder,
3791 match_end,
3792 subject_length);
3793 }
3794 SetLastMatchInfoNoCaptures(subject,
3795 last_match_array,
3796 match_start,
3797 match_end);
3798 return RegExpImpl::RE_SUCCESS;
3799 } else {
3800 return RegExpImpl::RE_FAILURE; // No matches at all.
3801 }
3802}
3803
3804
3805static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003806 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003807 Handle<String> subject,
3808 Handle<JSRegExp> regexp,
3809 Handle<JSArray> last_match_array,
3810 FixedArrayBuilder* builder) {
3811
3812 ASSERT(subject->IsFlat());
3813 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3814 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3815
3816 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003817 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003818
3819 RegExpImpl::IrregexpResult result =
3820 RegExpImpl::IrregexpExecOnce(regexp,
3821 subject,
3822 0,
3823 register_vector);
3824
3825 int capture_count = regexp->CaptureCount();
3826 int subject_length = subject->length();
3827
3828 // Position to search from.
3829 int pos = 0;
3830 // End of previous match. Differs from pos if match was empty.
3831 int match_end = 0;
3832 if (result == RegExpImpl::RE_SUCCESS) {
3833 // Need to keep a copy of the previous match for creating last_match_info
3834 // at the end, so we have two vectors that we swap between.
3835 OffsetsVector registers2(required_registers);
3836 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003837 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003838 do {
3839 int match_start = register_vector[0];
3840 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3841 if (match_end < match_start) {
3842 ReplacementStringBuilder::AddSubjectSlice(builder,
3843 match_end,
3844 match_start);
3845 }
3846 match_end = register_vector[1];
3847
3848 {
3849 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003850 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003851 // Arguments array to replace function is match, captures, index and
3852 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003853 Handle<FixedArray> elements =
3854 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003855 Handle<String> match;
3856 if (!first) {
3857 match = isolate->factory()->NewProperSubString(subject,
3858 match_start,
3859 match_end);
3860 } else {
3861 match = isolate->factory()->NewSubString(subject,
3862 match_start,
3863 match_end);
3864 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003865 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003866 for (int i = 1; i <= capture_count; i++) {
3867 int start = register_vector[i * 2];
3868 if (start >= 0) {
3869 int end = register_vector[i * 2 + 1];
3870 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003871 Handle<String> substring;
3872 if (!first) {
3873 substring = isolate->factory()->NewProperSubString(subject,
3874 start,
3875 end);
3876 } else {
3877 substring = isolate->factory()->NewSubString(subject, start, end);
3878 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003879 elements->set(i, *substring);
3880 } else {
3881 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003882 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003883 }
3884 }
3885 elements->set(capture_count + 1, Smi::FromInt(match_start));
3886 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003887 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003888 }
3889 // Swap register vectors, so the last successful match is in
3890 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003891 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003892 prev_register_vector = register_vector;
3893 register_vector = tmp;
3894
3895 if (match_end > match_start) {
3896 pos = match_end;
3897 } else {
3898 pos = match_end + 1;
3899 if (pos > subject_length) {
3900 break;
3901 }
3902 }
3903
3904 result = RegExpImpl::IrregexpExecOnce(regexp,
3905 subject,
3906 pos,
3907 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003908 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003909 } while (result == RegExpImpl::RE_SUCCESS);
3910
3911 if (result != RegExpImpl::RE_EXCEPTION) {
3912 // Finished matching, with at least one match.
3913 if (match_end < subject_length) {
3914 ReplacementStringBuilder::AddSubjectSlice(builder,
3915 match_end,
3916 subject_length);
3917 }
3918
3919 int last_match_capture_count = (capture_count + 1) * 2;
3920 int last_match_array_size =
3921 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3922 last_match_array->EnsureSize(last_match_array_size);
3923 AssertNoAllocation no_gc;
3924 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3925 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3926 RegExpImpl::SetLastSubject(elements, *subject);
3927 RegExpImpl::SetLastInput(elements, *subject);
3928 for (int i = 0; i < last_match_capture_count; i++) {
3929 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3930 }
3931 return RegExpImpl::RE_SUCCESS;
3932 }
3933 }
3934 // No matches at all, return failure or exception result directly.
3935 return result;
3936}
3937
3938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003939RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003940 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003941 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003942
3943 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003944 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003945 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3946 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3947 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3948
3949 ASSERT(last_match_info->HasFastElements());
3950 ASSERT(regexp->GetFlags().is_global());
3951 Handle<FixedArray> result_elements;
3952 if (result_array->HasFastElements()) {
3953 result_elements =
3954 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003955 }
3956 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003957 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003958 }
3959 FixedArrayBuilder builder(result_elements);
3960
3961 if (regexp->TypeTag() == JSRegExp::ATOM) {
3962 Handle<String> pattern(
3963 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003964 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003965 if (SearchStringMultiple(isolate, subject, pattern,
3966 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003967 return *builder.ToJSArray(result_array);
3968 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003969 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003970 }
3971
3972 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3973
3974 RegExpImpl::IrregexpResult result;
3975 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003976 result = SearchRegExpNoCaptureMultiple(isolate,
3977 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003978 regexp,
3979 last_match_info,
3980 &builder);
3981 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003982 result = SearchRegExpMultiple(isolate,
3983 subject,
3984 regexp,
3985 last_match_info,
3986 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003987 }
3988 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003989 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003990 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3991 return Failure::Exception();
3992}
3993
3994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003995RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003996 NoHandleAllocation ha;
3997 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003998 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003999 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004000
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004001 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004002 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004003 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004004 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004005 // Character array used for conversion.
4006 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004007 return isolate->heap()->
4008 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004009 }
4010 }
4011
4012 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004013 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004015 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 }
4017 if (isinf(value)) {
4018 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004019 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004021 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004023 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004024 MaybeObject* result =
4025 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026 DeleteArray(str);
4027 return result;
4028}
4029
4030
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004031RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 NoHandleAllocation ha;
4033 ASSERT(args.length() == 2);
4034
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004035 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004037 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 }
4039 if (isinf(value)) {
4040 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004041 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004043 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004044 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004045 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046 int f = FastD2I(f_number);
4047 RUNTIME_ASSERT(f >= 0);
4048 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004049 MaybeObject* res =
4050 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004051 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004052 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053}
4054
4055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004056RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
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 >= -1 && f <= 20);
4073 char* str = DoubleToExponentialCString(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_NumberToPrecision) {
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 <= 21);
4098 char* str = DoubleToPrecisionCString(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
4106// Returns a single character string where first character equals
4107// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004108static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004109 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004110 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004111 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004112 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004114 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004115}
4116
4117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004118MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4119 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004120 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004121 // Handle [] indexing on Strings
4122 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004123 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4124 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004125 }
4126
4127 // Handle [] indexing on String objects
4128 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004129 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4130 Handle<Object> result =
4131 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4132 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004133 }
4134
4135 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004136 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004137 }
4138
4139 return object->GetElement(index);
4140}
4141
4142
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004143MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4144 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004145 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004146 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004147
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004148 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004149 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004150 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004151 isolate->factory()->NewTypeError("non_object_property_load",
4152 HandleVector(args, 2));
4153 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004154 }
4155
4156 // Check if the given key is an array index.
4157 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004158 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004159 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160 }
4161
4162 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004163 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004165 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004167 bool has_pending_exception = false;
4168 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004169 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004170 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004171 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004172 }
4173
ager@chromium.org32912102009-01-16 10:38:43 +00004174 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004175 // the element if so.
4176 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004177 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004178 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004179 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180 }
4181}
4182
4183
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004184RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 NoHandleAllocation ha;
4186 ASSERT(args.length() == 2);
4187
4188 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004189 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004191 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004192}
4193
4194
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004195MaybeObject* TransitionElements(Handle<Object> object,
4196 ElementsKind to_kind,
4197 Isolate* isolate) {
4198 HandleScope scope(isolate);
4199 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4200 ElementsKind from_kind =
4201 Handle<JSObject>::cast(object)->map()->elements_kind();
4202 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004203 Handle<Object> result = JSObject::TransitionElementsKind(
4204 Handle<JSObject>::cast(object), to_kind);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004205 if (result.is_null()) return isolate->ThrowIllegalOperation();
4206 return *result;
4207 }
4208 return isolate->ThrowIllegalOperation();
4209}
4210
4211
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004212// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004213RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004214 NoHandleAllocation ha;
4215 ASSERT(args.length() == 2);
4216
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004217 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004218 // itself.
4219 //
4220 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004221 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004222 // global proxy object never has properties. This is the case
4223 // because the global proxy object forwards everything to its hidden
4224 // prototype including local lookups.
4225 //
4226 // Additionally, we need to make sure that we do not cache results
4227 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004228 if (args[0]->IsJSObject()) {
4229 if (!args[0]->IsJSGlobalProxy() &&
4230 !args[0]->IsAccessCheckNeeded() &&
4231 args[1]->IsString()) {
4232 JSObject* receiver = JSObject::cast(args[0]);
4233 String* key = String::cast(args[1]);
4234 if (receiver->HasFastProperties()) {
4235 // Attempt to use lookup cache.
4236 Map* receiver_map = receiver->map();
4237 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4238 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4239 if (offset != -1) {
4240 Object* value = receiver->FastPropertyAt(offset);
4241 return value->IsTheHole()
4242 ? isolate->heap()->undefined_value()
4243 : value;
4244 }
4245 // Lookup cache miss. Perform lookup and update the cache if
4246 // appropriate.
4247 LookupResult result(isolate);
4248 receiver->LocalLookup(key, &result);
4249 if (result.IsProperty() && result.type() == FIELD) {
4250 int offset = result.GetFieldIndex();
4251 keyed_lookup_cache->Update(receiver_map, key, offset);
4252 return receiver->FastPropertyAt(offset);
4253 }
4254 } else {
4255 // Attempt dictionary lookup.
4256 StringDictionary* dictionary = receiver->property_dictionary();
4257 int entry = dictionary->FindEntry(key);
4258 if ((entry != StringDictionary::kNotFound) &&
4259 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4260 Object* value = dictionary->ValueAt(entry);
4261 if (!receiver->IsGlobalObject()) return value;
4262 value = JSGlobalPropertyCell::cast(value)->value();
4263 if (!value->IsTheHole()) return value;
4264 // If value is the hole do the general lookup.
4265 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004266 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004267 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4268 // JSObject without a string key. If the key is a Smi, check for a
4269 // definite out-of-bounds access to elements, which is a strong indicator
4270 // that subsequent accesses will also call the runtime. Proactively
4271 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4272 // doubles for those future calls in the case that the elements would
4273 // become FAST_DOUBLE_ELEMENTS.
4274 Handle<JSObject> js_object(args.at<JSObject>(0));
4275 ElementsKind elements_kind = js_object->GetElementsKind();
4276 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4277 elements_kind == FAST_DOUBLE_ELEMENTS) {
4278 FixedArrayBase* elements = js_object->elements();
4279 if (args.at<Smi>(1)->value() >= elements->length()) {
4280 MaybeObject* maybe_object = TransitionElements(js_object,
4281 FAST_ELEMENTS,
4282 isolate);
4283 if (maybe_object->IsFailure()) return maybe_object;
4284 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004285 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004286 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004287 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4288 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004289 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004290 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004291 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004292 if (index >= 0 && index < str->length()) {
4293 Handle<Object> result = GetCharAt(str, index);
4294 return *result;
4295 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004296 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004297
4298 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004299 return Runtime::GetObjectProperty(isolate,
4300 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004301 args.at<Object>(1));
4302}
4303
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004304// Implements part of 8.12.9 DefineOwnProperty.
4305// There are 3 cases that lead here:
4306// Step 4b - define a new accessor property.
4307// Steps 9c & 12 - replace an existing data property with an accessor property.
4308// Step 12 - update an existing accessor property with an accessor or generic
4309// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004310RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004311 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004312 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004313 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4314 CONVERT_CHECKED(String, name, args[1]);
4315 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004316 Object* fun = args[3];
ager@chromium.org5c838252010-02-19 08:53:10 +00004317 CONVERT_CHECKED(Smi, flag_attr, args[4]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004318
ager@chromium.org5c838252010-02-19 08:53:10 +00004319 int unchecked = flag_attr->value();
4320 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004321 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004322
4323 RUNTIME_ASSERT(!obj->IsNull());
4324 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004325 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4326}
4327
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004328// Implements part of 8.12.9 DefineOwnProperty.
4329// There are 3 cases that lead here:
4330// Step 4a - define a new data property.
4331// Steps 9b & 12 - replace an existing accessor property with a data property.
4332// Step 12 - update an existing data property with a data or generic
4333// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004334RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004335 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004336 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004337 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4338 CONVERT_ARG_CHECKED(String, name, 1);
4339 Handle<Object> obj_value = args.at<Object>(2);
ager@chromium.org5c838252010-02-19 08:53:10 +00004340 CONVERT_CHECKED(Smi, flag, args[3]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004341
ager@chromium.org5c838252010-02-19 08:53:10 +00004342 int unchecked = flag->value();
4343 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004344 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4345
4346 // Check if this is an element.
4347 uint32_t index;
4348 bool is_element = name->AsArrayIndex(&index);
4349
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004350 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004351 // If elements are in fast case we always implicitly assume that:
4352 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004353 if (is_element && (attr != NONE ||
4354 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004355 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004356 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004357 // We do not need to do access checks here since these has already
4358 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004359 Handle<Object> proto(js_object->GetPrototype());
4360 // If proxy is detached, ignore the assignment. Alternatively,
4361 // we could throw an exception.
4362 if (proto->IsNull()) return *obj_value;
4363 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004364 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004365
4366 // Don't allow element properties to be redefined on objects with external
4367 // array elements.
4368 if (js_object->HasExternalArrayElements()) {
4369 Handle<Object> args[2] = { js_object, name };
4370 Handle<Object> error =
4371 isolate->factory()->NewTypeError("redef_external_array_element",
4372 HandleVector(args, 2));
4373 return isolate->Throw(*error);
4374 }
4375
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004376 Handle<SeededNumberDictionary> dictionary =
4377 JSObject::NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004378 // Make sure that we never go back to fast case.
4379 dictionary->set_requires_slow_elements();
4380 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004381 Handle<SeededNumberDictionary> extended_dictionary =
4382 SeededNumberDictionary::Set(dictionary, index, obj_value, details);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004383 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004384 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004385 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4386 } else {
4387 js_object->set_elements(*extended_dictionary);
4388 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004389 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004390 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004391 }
4392
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004393 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004394 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004395
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004396 // Special case for callback properties.
4397 if (result.IsProperty() && result.type() == CALLBACKS) {
4398 Object* callback = result.GetCallbackObject();
4399 // To be compatible with Safari we do not change the value on API objects
4400 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4401 // the value.
4402 if (callback->IsAccessorInfo()) {
4403 return isolate->heap()->undefined_value();
4404 }
4405 // Avoid redefining foreign callback as data property, just use the stored
4406 // setter to update the value instead.
4407 // TODO(mstarzinger): So far this only works if property attributes don't
4408 // change, this should be fixed once we cleanup the underlying code.
4409 if (callback->IsForeign() && result.GetAttributes() == attr) {
4410 return js_object->SetPropertyWithCallback(callback,
4411 *name,
4412 *obj_value,
4413 result.holder(),
4414 kStrictMode);
4415 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004416 }
4417
ager@chromium.org5c838252010-02-19 08:53:10 +00004418 // Take special care when attributes are different and there is already
4419 // a property. For simplicity we normalize the property which enables us
4420 // to not worry about changing the instance_descriptor and creating a new
4421 // map. The current version of SetObjectProperty does not handle attributes
4422 // correctly in the case where a property is a field and is reset with
4423 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004424 if (result.IsProperty() &&
4425 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004426 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004427 if (js_object->IsJSGlobalProxy()) {
4428 // Since the result is a property, the prototype will exist so
4429 // we don't have to check for null.
4430 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004431 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004432 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004433 // Use IgnoreAttributes version since a readonly property may be
4434 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004435 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4436 *obj_value,
4437 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004438 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004439
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004440 return Runtime::ForceSetObjectProperty(isolate,
4441 js_object,
4442 name,
4443 obj_value,
4444 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004445}
4446
4447
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004448// Special case for elements if any of the flags are true.
4449// If elements are in fast case we always implicitly assume that:
4450// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4451static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4452 Handle<JSObject> js_object,
4453 uint32_t index,
4454 Handle<Object> value,
4455 PropertyAttributes attr) {
4456 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004457 Handle<SeededNumberDictionary> dictionary =
4458 JSObject::NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004459 // Make sure that we never go back to fast case.
4460 dictionary->set_requires_slow_elements();
4461 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004462 Handle<SeededNumberDictionary> extended_dictionary =
4463 SeededNumberDictionary::Set(dictionary, index, value, details);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004464 if (*extended_dictionary != *dictionary) {
4465 js_object->set_elements(*extended_dictionary);
4466 }
4467 return *value;
4468}
4469
4470
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004471MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4472 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004473 Handle<Object> key,
4474 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004475 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004476 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004477 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004478
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004479 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004480 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004482 isolate->factory()->NewTypeError("non_object_property_store",
4483 HandleVector(args, 2));
4484 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004485 }
4486
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004487 if (object->IsJSProxy()) {
4488 bool has_pending_exception = false;
4489 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4490 if (has_pending_exception) return Failure::Exception();
4491 return JSProxy::cast(*object)->SetProperty(
4492 String::cast(*name), *value, attr, strict_mode);
4493 }
4494
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004495 // If the object isn't a JavaScript object, we ignore the store.
4496 if (!object->IsJSObject()) return *value;
4497
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004498 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4499
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004500 // Check if the given key is an array index.
4501 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004502 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004503 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4504 // of a string using [] notation. We need to support this too in
4505 // JavaScript.
4506 // In the case of a String object we just need to redirect the assignment to
4507 // the underlying string if the index is in range. Since the underlying
4508 // string does nothing with the assignment then we can ignore such
4509 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004510 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004511 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004512 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004514 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4515 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4516 }
4517
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004518 Handle<Object> result =
4519 JSObject::SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004520 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004521 return *value;
4522 }
4523
4524 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004525 Handle<Object> result;
4526 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004527 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4528 return NormalizeObjectSetElement(isolate,
4529 js_object,
4530 index,
4531 value,
4532 attr);
4533 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004534 result =
4535 JSObject::SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004536 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004537 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004538 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004539 result = JSReceiver::SetProperty(
4540 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004541 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004542 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004543 return *value;
4544 }
4545
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004546 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004547 bool has_pending_exception = false;
4548 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4549 if (has_pending_exception) return Failure::Exception();
4550 Handle<String> name = Handle<String>::cast(converted);
4551
4552 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004553 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004554 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004555 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004556 }
4557}
4558
4559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004560MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4561 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004562 Handle<Object> key,
4563 Handle<Object> value,
4564 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004565 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004566
4567 // Check if the given key is an array index.
4568 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004569 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004570 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4571 // of a string using [] notation. We need to support this too in
4572 // JavaScript.
4573 // In the case of a String object we just need to redirect the assignment to
4574 // the underlying string if the index is in range. Since the underlying
4575 // string does nothing with the assignment then we can ignore such
4576 // assignments.
4577 if (js_object->IsStringObjectWithCharacterAt(index)) {
4578 return *value;
4579 }
4580
whesse@chromium.org7b260152011-06-20 15:33:18 +00004581 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004582 }
4583
4584 if (key->IsString()) {
4585 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004586 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004587 } else {
4588 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004589 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004590 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4591 *value,
4592 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004593 }
4594 }
4595
4596 // Call-back into JavaScript to convert the key to a string.
4597 bool has_pending_exception = false;
4598 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4599 if (has_pending_exception) return Failure::Exception();
4600 Handle<String> name = Handle<String>::cast(converted);
4601
4602 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004603 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004604 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004605 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004606 }
4607}
4608
4609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004610MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004611 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004612 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004613 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004614
4615 // Check if the given key is an array index.
4616 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004617 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004618 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4619 // characters of a string using [] notation. In the case of a
4620 // String object we just need to redirect the deletion to the
4621 // underlying string if the index is in range. Since the
4622 // underlying string does nothing with the deletion, we can ignore
4623 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004624 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004625 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004626 }
4627
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004628 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004629 }
4630
4631 Handle<String> key_string;
4632 if (key->IsString()) {
4633 key_string = Handle<String>::cast(key);
4634 } else {
4635 // Call-back into JavaScript to convert the key to a string.
4636 bool has_pending_exception = false;
4637 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4638 if (has_pending_exception) return Failure::Exception();
4639 key_string = Handle<String>::cast(converted);
4640 }
4641
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004642 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004643 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004644}
4645
4646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004647RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004648 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004649 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004650
4651 Handle<Object> object = args.at<Object>(0);
4652 Handle<Object> key = args.at<Object>(1);
4653 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004654 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004655 RUNTIME_ASSERT(
4656 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004657 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004658 PropertyAttributes attributes =
4659 static_cast<PropertyAttributes>(unchecked_attributes);
4660
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004661 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004662 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004663 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4664 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004665 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004666
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004667 return Runtime::SetObjectProperty(isolate,
4668 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004669 key,
4670 value,
4671 attributes,
4672 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004673}
4674
4675
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004676RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4677 NoHandleAllocation ha;
4678 RUNTIME_ASSERT(args.length() == 1);
4679 Handle<Object> object = args.at<Object>(0);
4680 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4681}
4682
4683
4684RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4685 NoHandleAllocation ha;
4686 RUNTIME_ASSERT(args.length() == 1);
4687 Handle<Object> object = args.at<Object>(0);
4688 return TransitionElements(object, FAST_ELEMENTS, isolate);
4689}
4690
4691
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004692// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004693// This is used to decide if we should transform null and undefined
4694// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004695RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004696 NoHandleAllocation ha;
4697 RUNTIME_ASSERT(args.length() == 1);
4698
4699 Handle<Object> object = args.at<Object>(0);
4700
4701 if (object->IsJSFunction()) {
4702 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004703 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004704 }
4705 return isolate->heap()->undefined_value();
4706}
4707
4708
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004709RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4710 RUNTIME_ASSERT(args.length() == 5);
4711 CONVERT_ARG_CHECKED(JSObject, object, 0);
4712 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4713 Handle<Object> value = args.at<Object>(2);
4714 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4715 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4716 HandleScope scope;
4717
4718 Object* raw_boilerplate_object = literals->get(literal_index);
4719 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4720#if DEBUG
4721 ElementsKind elements_kind = object->GetElementsKind();
4722#endif
4723 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4724 // Smis should never trigger transitions.
4725 ASSERT(!value->IsSmi());
4726
4727 if (value->IsNumber()) {
4728 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004729 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4730 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004731 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4732 FixedDoubleArray* double_array =
4733 FixedDoubleArray::cast(object->elements());
4734 HeapNumber* number = HeapNumber::cast(*value);
4735 double_array->set(store_index, number->Number());
4736 } else {
4737 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4738 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004739 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4740 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004741 FixedArray* object_array =
4742 FixedArray::cast(object->elements());
4743 object_array->set(store_index, *value);
4744 }
4745 return *object;
4746}
4747
4748
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004749// Set a local property, even if it is READ_ONLY. If the property does not
4750// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004751RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004752 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004753 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004754 CONVERT_CHECKED(JSObject, object, args[0]);
4755 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004756 // Compute attributes.
4757 PropertyAttributes attributes = NONE;
4758 if (args.length() == 4) {
4759 CONVERT_CHECKED(Smi, value_obj, args[3]);
4760 int unchecked_value = value_obj->value();
4761 // Only attribute bits should be set.
4762 RUNTIME_ASSERT(
4763 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4764 attributes = static_cast<PropertyAttributes>(unchecked_value);
4765 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004766
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004767 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004768 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769}
4770
4771
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004772RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004773 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004774 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004776 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004777 CONVERT_CHECKED(String, key, args[1]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004778 CONVERT_STRICT_MODE_ARG(strict_mode, 2);
4779 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004780 ? JSReceiver::STRICT_DELETION
4781 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004782}
4783
4784
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004785static Object* HasLocalPropertyImplementation(Isolate* isolate,
4786 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004787 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004788 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004789 // Handle hidden prototypes. If there's a hidden prototype above this thing
4790 // then we have to check it for properties, because they are supposed to
4791 // look like they are on this object.
4792 Handle<Object> proto(object->GetPrototype());
4793 if (proto->IsJSObject() &&
4794 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004795 return HasLocalPropertyImplementation(isolate,
4796 Handle<JSObject>::cast(proto),
4797 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004798 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004799 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004800}
4801
4802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004803RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004804 NoHandleAllocation ha;
4805 ASSERT(args.length() == 2);
4806 CONVERT_CHECKED(String, key, args[1]);
4807
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004808 uint32_t index;
4809 const bool key_is_array_index = key->AsArrayIndex(&index);
4810
ager@chromium.org9085a012009-05-11 19:22:57 +00004811 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004812 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004813 if (obj->IsJSObject()) {
4814 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004815 // Fast case: either the key is a real named property or it is not
4816 // an array index and there are no interceptors or hidden
4817 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004818 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004819 Map* map = object->map();
4820 if (!key_is_array_index &&
4821 !map->has_named_interceptor() &&
4822 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4823 return isolate->heap()->false_value();
4824 }
4825 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004826 HandleScope scope(isolate);
4827 return HasLocalPropertyImplementation(isolate,
4828 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004829 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004830 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004832 String* string = String::cast(obj);
4833 if (index < static_cast<uint32_t>(string->length())) {
4834 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004835 }
4836 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004837 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004838}
4839
4840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004841RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004842 NoHandleAllocation na;
4843 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004844 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4845 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004846
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004847 bool result = receiver->HasProperty(key);
4848 if (isolate->has_pending_exception()) return Failure::Exception();
4849 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004850}
4851
4852
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004853RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004854 NoHandleAllocation na;
4855 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004856 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4857 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004858
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004859 bool result = receiver->HasElement(index->value());
4860 if (isolate->has_pending_exception()) return Failure::Exception();
4861 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004862}
4863
4864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004865RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866 NoHandleAllocation ha;
4867 ASSERT(args.length() == 2);
4868
4869 CONVERT_CHECKED(JSObject, object, args[0]);
4870 CONVERT_CHECKED(String, key, args[1]);
4871
4872 uint32_t index;
4873 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004874 JSObject::LocalElementType type = object->HasLocalElement(index);
4875 switch (type) {
4876 case JSObject::UNDEFINED_ELEMENT:
4877 case JSObject::STRING_CHARACTER_ELEMENT:
4878 return isolate->heap()->false_value();
4879 case JSObject::INTERCEPTED_ELEMENT:
4880 case JSObject::FAST_ELEMENT:
4881 return isolate->heap()->true_value();
4882 case JSObject::DICTIONARY_ELEMENT: {
4883 if (object->IsJSGlobalProxy()) {
4884 Object* proto = object->GetPrototype();
4885 if (proto->IsNull()) {
4886 return isolate->heap()->false_value();
4887 }
4888 ASSERT(proto->IsJSGlobalObject());
4889 object = JSObject::cast(proto);
4890 }
4891 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004892 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004893 if (elements->map() ==
4894 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004895 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004896 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004897 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004898 }
4899 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004900 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004901 PropertyDetails details = dictionary->DetailsAt(entry);
4902 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4903 }
4904 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004905 }
4906
ager@chromium.org870a0b62008-11-04 11:43:05 +00004907 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004908 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004909}
4910
4911
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004912RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004913 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004914 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004915 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4916 bool threw = false;
4917 Handle<JSArray> result = GetKeysFor(object, &threw);
4918 if (threw) return Failure::Exception();
4919 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004920}
4921
4922
4923// Returns either a FixedArray as Runtime_GetPropertyNames,
4924// or, if the given object has an enum cache that contains
4925// all enumerable properties of the object and its prototypes
4926// have none, the map of the object. This is used to speed up
4927// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004928RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004929 ASSERT(args.length() == 1);
4930
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004931 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004932
4933 if (raw_object->IsSimpleEnum()) return raw_object->map();
4934
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004935 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004936 Handle<JSReceiver> object(raw_object);
4937 bool threw = false;
4938 Handle<FixedArray> content =
4939 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4940 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004941
4942 // Test again, since cache may have been built by preceding call.
4943 if (object->IsSimpleEnum()) return object->map();
4944
4945 return *content;
4946}
4947
4948
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004949// Find the length of the prototype chain that is to to handled as one. If a
4950// prototype object is hidden it is to be viewed as part of the the object it
4951// is prototype for.
4952static int LocalPrototypeChainLength(JSObject* obj) {
4953 int count = 1;
4954 Object* proto = obj->GetPrototype();
4955 while (proto->IsJSObject() &&
4956 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4957 count++;
4958 proto = JSObject::cast(proto)->GetPrototype();
4959 }
4960 return count;
4961}
4962
4963
4964// Return the names of the local named properties.
4965// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004966RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004967 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004968 ASSERT(args.length() == 1);
4969 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004970 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004971 }
4972 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4973
4974 // Skip the global proxy as it has no properties and always delegates to the
4975 // real global object.
4976 if (obj->IsJSGlobalProxy()) {
4977 // Only collect names if access is permitted.
4978 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004979 !isolate->MayNamedAccess(*obj,
4980 isolate->heap()->undefined_value(),
4981 v8::ACCESS_KEYS)) {
4982 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4983 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004984 }
4985 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4986 }
4987
4988 // Find the number of objects making up this.
4989 int length = LocalPrototypeChainLength(*obj);
4990
4991 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004992 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004993 int total_property_count = 0;
4994 Handle<JSObject> jsproto = obj;
4995 for (int i = 0; i < length; i++) {
4996 // Only collect names if access is permitted.
4997 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004998 !isolate->MayNamedAccess(*jsproto,
4999 isolate->heap()->undefined_value(),
5000 v8::ACCESS_KEYS)) {
5001 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
5002 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005003 }
5004 int n;
5005 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
5006 local_property_count[i] = n;
5007 total_property_count += n;
5008 if (i < length - 1) {
5009 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5010 }
5011 }
5012
5013 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005014 Handle<FixedArray> names =
5015 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005016
5017 // Get the property names.
5018 jsproto = obj;
5019 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005020 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005021 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005022 jsproto->GetLocalPropertyNames(*names, next_copy_index);
5023 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005024 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005025 proto_with_hidden_properties++;
5026 }
5027 if (i < length - 1) {
5028 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5029 }
5030 }
5031
5032 // Filter out name of hidden propeties object.
5033 if (proto_with_hidden_properties > 0) {
5034 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005035 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005036 names->length() - proto_with_hidden_properties);
5037 int dest_pos = 0;
5038 for (int i = 0; i < total_property_count; i++) {
5039 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005040 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005041 continue;
5042 }
5043 names->set(dest_pos++, name);
5044 }
5045 }
5046
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005047 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005048}
5049
5050
5051// Return the names of the local indexed properties.
5052// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005053RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005054 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005055 ASSERT(args.length() == 1);
5056 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005057 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005058 }
5059 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5060
5061 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005062 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005063 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005064 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005065}
5066
5067
5068// Return information on whether an object has a named or indexed interceptor.
5069// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005070RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005071 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005072 ASSERT(args.length() == 1);
5073 if (!args[0]->IsJSObject()) {
5074 return Smi::FromInt(0);
5075 }
5076 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5077
5078 int result = 0;
5079 if (obj->HasNamedInterceptor()) result |= 2;
5080 if (obj->HasIndexedInterceptor()) result |= 1;
5081
5082 return Smi::FromInt(result);
5083}
5084
5085
5086// Return property names from named interceptor.
5087// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005088RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005089 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005090 ASSERT(args.length() == 1);
5091 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5092
5093 if (obj->HasNamedInterceptor()) {
5094 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5095 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5096 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005097 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005098}
5099
5100
5101// Return element names from indexed interceptor.
5102// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005103RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005104 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005105 ASSERT(args.length() == 1);
5106 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5107
5108 if (obj->HasIndexedInterceptor()) {
5109 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5110 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5111 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005112 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005113}
5114
5115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005116RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005117 ASSERT_EQ(args.length(), 1);
5118 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005119 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005120 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005121
5122 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005123 // Do access checks before going to the global object.
5124 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005125 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005126 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005127 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5128 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005129 }
5130
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005131 Handle<Object> proto(object->GetPrototype());
5132 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005133 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005134 object = Handle<JSObject>::cast(proto);
5135 }
5136
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005137 bool threw = false;
5138 Handle<FixedArray> contents =
5139 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5140 if (threw) return Failure::Exception();
5141
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005142 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5143 // property array and since the result is mutable we have to create
5144 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005145 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005146 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005147 for (int i = 0; i < length; i++) {
5148 Object* entry = contents->get(i);
5149 if (entry->IsString()) {
5150 copy->set(i, entry);
5151 } else {
5152 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005153 HandleScope scope(isolate);
5154 Handle<Object> entry_handle(entry, isolate);
5155 Handle<Object> entry_str =
5156 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005157 copy->set(i, *entry_str);
5158 }
5159 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005160 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005161}
5162
5163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005164RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005165 NoHandleAllocation ha;
5166 ASSERT(args.length() == 1);
5167
5168 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005169 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005170 it.AdvanceToArgumentsFrame();
5171 JavaScriptFrame* frame = it.frame();
5172
5173 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005174 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005175
5176 // Try to convert the key to an index. If successful and within
5177 // index return the the argument from the frame.
5178 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005179 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005180 return frame->GetParameter(index);
5181 }
5182
5183 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005184 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005185 bool exception = false;
5186 Handle<Object> converted =
5187 Execution::ToString(args.at<Object>(0), &exception);
5188 if (exception) return Failure::Exception();
5189 Handle<String> key = Handle<String>::cast(converted);
5190
5191 // Try to convert the string key into an array index.
5192 if (key->AsArrayIndex(&index)) {
5193 if (index < n) {
5194 return frame->GetParameter(index);
5195 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005196 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005197 }
5198 }
5199
5200 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005201 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5202 if (key->Equals(isolate->heap()->callee_symbol())) {
5203 Object* function = frame->function();
5204 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005205 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005206 return isolate->Throw(*isolate->factory()->NewTypeError(
5207 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5208 }
5209 return function;
5210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005211
5212 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005213 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005214}
5215
5216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005217RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005218 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005219 Object* object = args[0];
5220 return (object->IsJSObject() && !object->IsGlobalObject())
5221 ? JSObject::cast(object)->TransformToFastProperties(0)
5222 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005223}
5224
5225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005226RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005227 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005228 Object* obj = args[0];
5229 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5230 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5231 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005232}
5233
5234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005235RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005236 NoHandleAllocation ha;
5237 ASSERT(args.length() == 1);
5238
5239 return args[0]->ToBoolean();
5240}
5241
5242
5243// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5244// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005245RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005246 NoHandleAllocation ha;
5247
5248 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005249 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005250 HeapObject* heap_obj = HeapObject::cast(obj);
5251
5252 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005253 if (heap_obj->map()->is_undetectable()) {
5254 return isolate->heap()->undefined_symbol();
5255 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005256
5257 InstanceType instance_type = heap_obj->map()->instance_type();
5258 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005259 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005260 }
5261
5262 switch (instance_type) {
5263 case ODDBALL_TYPE:
5264 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005265 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005266 }
5267 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005268 return FLAG_harmony_typeof
5269 ? isolate->heap()->null_symbol()
5270 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005271 }
5272 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005273 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005274 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005275 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005276 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005277 default:
5278 // For any kind of object not handled above, the spec rule for
5279 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005280 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005281 }
5282}
5283
5284
lrn@chromium.org25156de2010-04-06 13:10:27 +00005285static bool AreDigits(const char*s, int from, int to) {
5286 for (int i = from; i < to; i++) {
5287 if (s[i] < '0' || s[i] > '9') return false;
5288 }
5289
5290 return true;
5291}
5292
5293
5294static int ParseDecimalInteger(const char*s, int from, int to) {
5295 ASSERT(to - from < 10); // Overflow is not possible.
5296 ASSERT(from < to);
5297 int d = s[from] - '0';
5298
5299 for (int i = from + 1; i < to; i++) {
5300 d = 10 * d + (s[i] - '0');
5301 }
5302
5303 return d;
5304}
5305
5306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005307RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005308 NoHandleAllocation ha;
5309 ASSERT(args.length() == 1);
5310 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005311 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005312
5313 // Fast case: short integer or some sorts of junk values.
5314 int len = subject->length();
5315 if (subject->IsSeqAsciiString()) {
5316 if (len == 0) return Smi::FromInt(0);
5317
5318 char const* data = SeqAsciiString::cast(subject)->GetChars();
5319 bool minus = (data[0] == '-');
5320 int start_pos = (minus ? 1 : 0);
5321
5322 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005323 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005324 } else if (data[start_pos] > '9') {
5325 // Fast check for a junk value. A valid string may start from a
5326 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5327 // the 'I' character ('Infinity'). All of that have codes not greater than
5328 // '9' except 'I'.
5329 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005330 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005331 }
5332 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5333 // The maximal/minimal smi has 10 digits. If the string has less digits we
5334 // know it will fit into the smi-data type.
5335 int d = ParseDecimalInteger(data, start_pos, len);
5336 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005337 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005338 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005339 } else if (!subject->HasHashCode() &&
5340 len <= String::kMaxArrayIndexSize &&
5341 (len == 1 || data[0] != '0')) {
5342 // String hash is not calculated yet but all the data are present.
5343 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005344 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005345#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005346 subject->Hash(); // Force hash calculation.
5347 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5348 static_cast<int>(hash));
5349#endif
5350 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005351 }
5352 return Smi::FromInt(d);
5353 }
5354 }
5355
5356 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005357 return isolate->heap()->NumberFromDouble(
5358 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005359}
5360
5361
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005362RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005363 NoHandleAllocation ha;
5364 ASSERT(args.length() == 1);
5365
5366 CONVERT_CHECKED(JSArray, codes, args[0]);
5367 int length = Smi::cast(codes->length())->value();
5368
5369 // Check if the string can be ASCII.
5370 int i;
5371 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005372 Object* element;
5373 { MaybeObject* maybe_element = codes->GetElement(i);
5374 // We probably can't get an exception here, but just in order to enforce
5375 // the checking of inputs in the runtime calls we check here.
5376 if (!maybe_element->ToObject(&element)) return maybe_element;
5377 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005378 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5379 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5380 break;
5381 }
5382
lrn@chromium.org303ada72010-10-27 09:33:13 +00005383 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005384 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005385 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005386 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005387 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005388 }
5389
lrn@chromium.org303ada72010-10-27 09:33:13 +00005390 Object* object = NULL;
5391 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005392 String* result = String::cast(object);
5393 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005394 Object* element;
5395 { MaybeObject* maybe_element = codes->GetElement(i);
5396 if (!maybe_element->ToObject(&element)) return maybe_element;
5397 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005398 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005399 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005400 }
5401 return result;
5402}
5403
5404
5405// kNotEscaped is generated by the following:
5406//
5407// #!/bin/perl
5408// for (my $i = 0; $i < 256; $i++) {
5409// print "\n" if $i % 16 == 0;
5410// my $c = chr($i);
5411// my $escaped = 1;
5412// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5413// print $escaped ? "0, " : "1, ";
5414// }
5415
5416
5417static bool IsNotEscaped(uint16_t character) {
5418 // Only for 8 bit characters, the rest are always escaped (in a different way)
5419 ASSERT(character < 256);
5420 static const char kNotEscaped[256] = {
5421 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5422 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5423 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5424 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5425 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5426 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5427 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5428 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
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, 0, 0, 0, 0, 0, 0,
5432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5434 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5435 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5436 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5437 };
5438 return kNotEscaped[character] != 0;
5439}
5440
5441
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005442RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005443 const char hex_chars[] = "0123456789ABCDEF";
5444 NoHandleAllocation ha;
5445 ASSERT(args.length() == 1);
5446 CONVERT_CHECKED(String, source, args[0]);
5447
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005448 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005449
5450 int escaped_length = 0;
5451 int length = source->length();
5452 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005453 Access<StringInputBuffer> buffer(
5454 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005455 buffer->Reset(source);
5456 while (buffer->has_more()) {
5457 uint16_t character = buffer->GetNext();
5458 if (character >= 256) {
5459 escaped_length += 6;
5460 } else if (IsNotEscaped(character)) {
5461 escaped_length++;
5462 } else {
5463 escaped_length += 3;
5464 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005465 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005466 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005467 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005468 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005469 return Failure::OutOfMemoryException();
5470 }
5471 }
5472 }
5473 // No length change implies no change. Return original string if no change.
5474 if (escaped_length == length) {
5475 return source;
5476 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005477 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005478 { MaybeObject* maybe_o =
5479 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005480 if (!maybe_o->ToObject(&o)) return maybe_o;
5481 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005482 String* destination = String::cast(o);
5483 int dest_position = 0;
5484
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005485 Access<StringInputBuffer> buffer(
5486 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005487 buffer->Rewind();
5488 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005489 uint16_t chr = buffer->GetNext();
5490 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005491 destination->Set(dest_position, '%');
5492 destination->Set(dest_position+1, 'u');
5493 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5494 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5495 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5496 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005498 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005499 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005500 dest_position++;
5501 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005502 destination->Set(dest_position, '%');
5503 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5504 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005505 dest_position += 3;
5506 }
5507 }
5508 return destination;
5509}
5510
5511
5512static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5513 static const signed char kHexValue['g'] = {
5514 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5515 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5516 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5517 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5518 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5519 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5520 -1, 10, 11, 12, 13, 14, 15 };
5521
5522 if (character1 > 'f') return -1;
5523 int hi = kHexValue[character1];
5524 if (hi == -1) return -1;
5525 if (character2 > 'f') return -1;
5526 int lo = kHexValue[character2];
5527 if (lo == -1) return -1;
5528 return (hi << 4) + lo;
5529}
5530
5531
ager@chromium.org870a0b62008-11-04 11:43:05 +00005532static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005533 int i,
5534 int length,
5535 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005536 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005537 int32_t hi = 0;
5538 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005539 if (character == '%' &&
5540 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005541 source->Get(i + 1) == 'u' &&
5542 (hi = TwoDigitHex(source->Get(i + 2),
5543 source->Get(i + 3))) != -1 &&
5544 (lo = TwoDigitHex(source->Get(i + 4),
5545 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005546 *step = 6;
5547 return (hi << 8) + lo;
5548 } else if (character == '%' &&
5549 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005550 (lo = TwoDigitHex(source->Get(i + 1),
5551 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005552 *step = 3;
5553 return lo;
5554 } else {
5555 *step = 1;
5556 return character;
5557 }
5558}
5559
5560
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005561RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005562 NoHandleAllocation ha;
5563 ASSERT(args.length() == 1);
5564 CONVERT_CHECKED(String, source, args[0]);
5565
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005566 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005567
5568 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005569 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005570
5571 int unescaped_length = 0;
5572 for (int i = 0; i < length; unescaped_length++) {
5573 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005574 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005575 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005576 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577 i += step;
5578 }
5579
5580 // No length change implies no change. Return original string if no change.
5581 if (unescaped_length == length)
5582 return source;
5583
lrn@chromium.org303ada72010-10-27 09:33:13 +00005584 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005585 { MaybeObject* maybe_o =
5586 ascii ?
5587 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5588 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005589 if (!maybe_o->ToObject(&o)) return maybe_o;
5590 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005591 String* destination = String::cast(o);
5592
5593 int dest_position = 0;
5594 for (int i = 0; i < length; dest_position++) {
5595 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005596 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005597 i += step;
5598 }
5599 return destination;
5600}
5601
5602
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005603static const unsigned int kQuoteTableLength = 128u;
5604
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005605static const int kJsonQuotesCharactersPerEntry = 8;
5606static const char* const JsonQuotes =
5607 "\\u0000 \\u0001 \\u0002 \\u0003 "
5608 "\\u0004 \\u0005 \\u0006 \\u0007 "
5609 "\\b \\t \\n \\u000b "
5610 "\\f \\r \\u000e \\u000f "
5611 "\\u0010 \\u0011 \\u0012 \\u0013 "
5612 "\\u0014 \\u0015 \\u0016 \\u0017 "
5613 "\\u0018 \\u0019 \\u001a \\u001b "
5614 "\\u001c \\u001d \\u001e \\u001f "
5615 " ! \\\" # "
5616 "$ % & ' "
5617 "( ) * + "
5618 ", - . / "
5619 "0 1 2 3 "
5620 "4 5 6 7 "
5621 "8 9 : ; "
5622 "< = > ? "
5623 "@ A B C "
5624 "D E F G "
5625 "H I J K "
5626 "L M N O "
5627 "P Q R S "
5628 "T U V W "
5629 "X Y Z [ "
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 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005639
5640
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005641// For a string that is less than 32k characters it should always be
5642// possible to allocate it in new space.
5643static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5644
5645
5646// Doing JSON quoting cannot make the string more than this many times larger.
5647static const int kJsonQuoteWorstCaseBlowup = 6;
5648
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005649static const int kSpaceForQuotesAndComma = 3;
5650static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005651
5652// Covers the entire ASCII range (all other characters are unchanged by JSON
5653// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005654static const byte JsonQuoteLengths[kQuoteTableLength] = {
5655 6, 6, 6, 6, 6, 6, 6, 6,
5656 2, 2, 2, 6, 2, 2, 6, 6,
5657 6, 6, 6, 6, 6, 6, 6, 6,
5658 6, 6, 6, 6, 6, 6, 6, 6,
5659 1, 1, 2, 1, 1, 1, 1, 1,
5660 1, 1, 1, 1, 1, 1, 1, 1,
5661 1, 1, 1, 1, 1, 1, 1, 1,
5662 1, 1, 1, 1, 1, 1, 1, 1,
5663 1, 1, 1, 1, 1, 1, 1, 1,
5664 1, 1, 1, 1, 1, 1, 1, 1,
5665 1, 1, 1, 1, 1, 1, 1, 1,
5666 1, 1, 1, 1, 2, 1, 1, 1,
5667 1, 1, 1, 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};
5672
5673
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005674template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005675MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005676
5677
5678template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005679MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5680 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005681}
5682
5683
5684template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005685MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5686 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005687}
5688
5689
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005690template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005691static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5692 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005693 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005694 const Char* read_cursor = characters.start();
5695 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005696 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005697 int quoted_length = kSpaceForQuotes;
5698 while (read_cursor < end) {
5699 Char c = *(read_cursor++);
5700 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5701 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005702 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005703 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005704 }
5705 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005706 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5707 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005708 Object* new_object;
5709 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005710 return new_alloc;
5711 }
5712 StringType* new_string = StringType::cast(new_object);
5713
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005714 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005715 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005716 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005717 *(write_cursor++) = '"';
5718
5719 read_cursor = characters.start();
5720 while (read_cursor < end) {
5721 Char c = *(read_cursor++);
5722 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5723 *(write_cursor++) = c;
5724 } else {
5725 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5726 const char* replacement = JsonQuotes +
5727 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5728 for (int i = 0; i < len; i++) {
5729 *write_cursor++ = *replacement++;
5730 }
5731 }
5732 }
5733 *(write_cursor++) = '"';
5734 return new_string;
5735}
5736
5737
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005738template <typename SinkChar, typename SourceChar>
5739static inline SinkChar* WriteQuoteJsonString(
5740 Isolate* isolate,
5741 SinkChar* write_cursor,
5742 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005743 // SinkChar is only char if SourceChar is guaranteed to be char.
5744 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005745 const SourceChar* read_cursor = characters.start();
5746 const SourceChar* end = read_cursor + characters.length();
5747 *(write_cursor++) = '"';
5748 while (read_cursor < end) {
5749 SourceChar c = *(read_cursor++);
5750 if (sizeof(SourceChar) > 1u &&
5751 static_cast<unsigned>(c) >= kQuoteTableLength) {
5752 *(write_cursor++) = static_cast<SinkChar>(c);
5753 } else {
5754 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5755 const char* replacement = JsonQuotes +
5756 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5757 write_cursor[0] = replacement[0];
5758 if (len > 1) {
5759 write_cursor[1] = replacement[1];
5760 if (len > 2) {
5761 ASSERT(len == 6);
5762 write_cursor[2] = replacement[2];
5763 write_cursor[3] = replacement[3];
5764 write_cursor[4] = replacement[4];
5765 write_cursor[5] = replacement[5];
5766 }
5767 }
5768 write_cursor += len;
5769 }
5770 }
5771 *(write_cursor++) = '"';
5772 return write_cursor;
5773}
5774
5775
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005776template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005777static MaybeObject* QuoteJsonString(Isolate* isolate,
5778 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005779 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005780 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005781 int worst_case_length =
5782 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005783 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005784 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005785 }
5786
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005787 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5788 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005789 Object* new_object;
5790 if (!new_alloc->ToObject(&new_object)) {
5791 return new_alloc;
5792 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005794 // Even if our string is small enough to fit in new space we still have to
5795 // handle it being allocated in old space as may happen in the third
5796 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5797 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005798 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005799 }
5800 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005801 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005802
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005803 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005804 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005805 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005806 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5807 write_cursor,
5808 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005809 int final_length = static_cast<int>(
5810 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005811 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005812 isolate->heap()->new_space()->
5813 template ShrinkStringAtAllocationBoundary<StringType>(
5814 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005815 return new_string;
5816}
5817
5818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005819RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005820 NoHandleAllocation ha;
5821 CONVERT_CHECKED(String, str, args[0]);
5822 if (!str->IsFlat()) {
5823 MaybeObject* try_flatten = str->TryFlatten();
5824 Object* flat;
5825 if (!try_flatten->ToObject(&flat)) {
5826 return try_flatten;
5827 }
5828 str = String::cast(flat);
5829 ASSERT(str->IsFlat());
5830 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005831 String::FlatContent flat = str->GetFlatContent();
5832 ASSERT(flat.IsFlat());
5833 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005834 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005835 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005836 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005837 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005838 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005839 }
5840}
5841
5842
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005843RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005844 NoHandleAllocation ha;
5845 CONVERT_CHECKED(String, str, args[0]);
5846 if (!str->IsFlat()) {
5847 MaybeObject* try_flatten = str->TryFlatten();
5848 Object* flat;
5849 if (!try_flatten->ToObject(&flat)) {
5850 return try_flatten;
5851 }
5852 str = String::cast(flat);
5853 ASSERT(str->IsFlat());
5854 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005855 String::FlatContent flat = str->GetFlatContent();
5856 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005857 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005858 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005859 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005860 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005861 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005862 }
5863}
5864
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005865
5866template <typename Char, typename StringType>
5867static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5868 FixedArray* array,
5869 int worst_case_length) {
5870 int length = array->length();
5871
5872 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5873 worst_case_length);
5874 Object* new_object;
5875 if (!new_alloc->ToObject(&new_object)) {
5876 return new_alloc;
5877 }
5878 if (!isolate->heap()->new_space()->Contains(new_object)) {
5879 // Even if our string is small enough to fit in new space we still have to
5880 // handle it being allocated in old space as may happen in the third
5881 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5882 // CEntryStub::GenerateCore.
5883 return isolate->heap()->undefined_value();
5884 }
5885 AssertNoAllocation no_gc;
5886 StringType* new_string = StringType::cast(new_object);
5887 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5888
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005889 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005890 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005891 *(write_cursor++) = '[';
5892 for (int i = 0; i < length; i++) {
5893 if (i != 0) *(write_cursor++) = ',';
5894 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005895 String::FlatContent content = str->GetFlatContent();
5896 ASSERT(content.IsFlat());
5897 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005898 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5899 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005900 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005901 } else {
5902 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5903 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005904 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005905 }
5906 }
5907 *(write_cursor++) = ']';
5908
5909 int final_length = static_cast<int>(
5910 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005911 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005912 isolate->heap()->new_space()->
5913 template ShrinkStringAtAllocationBoundary<StringType>(
5914 new_string, final_length);
5915 return new_string;
5916}
5917
5918
5919RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5920 NoHandleAllocation ha;
5921 ASSERT(args.length() == 1);
5922 CONVERT_CHECKED(JSArray, array, args[0]);
5923
5924 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5925 FixedArray* elements = FixedArray::cast(array->elements());
5926 int n = elements->length();
5927 bool ascii = true;
5928 int total_length = 0;
5929
5930 for (int i = 0; i < n; i++) {
5931 Object* elt = elements->get(i);
5932 if (!elt->IsString()) return isolate->heap()->undefined_value();
5933 String* element = String::cast(elt);
5934 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5935 total_length += element->length();
5936 if (ascii && element->IsTwoByteRepresentation()) {
5937 ascii = false;
5938 }
5939 }
5940
5941 int worst_case_length =
5942 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5943 + total_length * kJsonQuoteWorstCaseBlowup;
5944
5945 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5946 return isolate->heap()->undefined_value();
5947 }
5948
5949 if (ascii) {
5950 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5951 elements,
5952 worst_case_length);
5953 } else {
5954 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5955 elements,
5956 worst_case_length);
5957 }
5958}
5959
5960
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005961RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005962 NoHandleAllocation ha;
5963
5964 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005965 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005966
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005967 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005968
lrn@chromium.org25156de2010-04-06 13:10:27 +00005969 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005970 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005971 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005972}
5973
5974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005975RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005976 NoHandleAllocation ha;
5977 CONVERT_CHECKED(String, str, args[0]);
5978
5979 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005980 double value = StringToDouble(isolate->unicode_cache(),
5981 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982
5983 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005984 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005985}
5986
5987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005989MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005990 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005991 String* s,
5992 int length,
5993 int input_string_length,
5994 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005995 // We try this twice, once with the assumption that the result is no longer
5996 // than the input and, if that assumption breaks, again with the exact
5997 // length. This may not be pretty, but it is nicer than what was here before
5998 // and I hereby claim my vaffel-is.
5999 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000 // Allocate the resulting string.
6001 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006002 // NOTE: This assumes that the upper/lower case of an ASCII
6003 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006004 // might break in the future if we implement more context and locale
6005 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006006 Object* o;
6007 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006008 ? isolate->heap()->AllocateRawAsciiString(length)
6009 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006010 if (!maybe_o->ToObject(&o)) return maybe_o;
6011 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006012 String* result = String::cast(o);
6013 bool has_changed_character = false;
6014
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015 // Convert all characters to upper case, assuming that they will fit
6016 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006017 Access<StringInputBuffer> buffer(
6018 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006019 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006020 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006021 // We can assume that the string is not empty
6022 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006023 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006024 bool has_next = buffer->has_more();
6025 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 int char_length = mapping->get(current, next, chars);
6027 if (char_length == 0) {
6028 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006029 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030 i++;
6031 } else if (char_length == 1) {
6032 // Common case: converting the letter resulted in one character.
6033 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006034 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006035 has_changed_character = true;
6036 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006037 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 // We've assumed that the result would be as long as the
6039 // input but here is a character that converts to several
6040 // characters. No matter, we calculate the exact length
6041 // of the result and try the whole thing again.
6042 //
6043 // Note that this leaves room for optimization. We could just
6044 // memcpy what we already have to the result string. Also,
6045 // the result string is the last object allocated we could
6046 // "realloc" it and probably, in the vast majority of cases,
6047 // extend the existing string to be able to hold the full
6048 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006049 int next_length = 0;
6050 if (has_next) {
6051 next_length = mapping->get(next, 0, chars);
6052 if (next_length == 0) next_length = 1;
6053 }
6054 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006055 while (buffer->has_more()) {
6056 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006057 // NOTE: we use 0 as the next character here because, while
6058 // the next character may affect what a character converts to,
6059 // it does not in any case affect the length of what it convert
6060 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006061 int char_length = mapping->get(current, 0, chars);
6062 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006063 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006064 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006065 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006066 return Failure::OutOfMemoryException();
6067 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006068 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006069 // Try again with the real length.
6070 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006071 } else {
6072 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006073 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006074 i++;
6075 }
6076 has_changed_character = true;
6077 }
6078 current = next;
6079 }
6080 if (has_changed_character) {
6081 return result;
6082 } else {
6083 // If we didn't actually change anything in doing the conversion
6084 // we simple return the result and let the converted string
6085 // become garbage; there is no reason to keep two identical strings
6086 // alive.
6087 return s;
6088 }
6089}
6090
6091
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006092namespace {
6093
lrn@chromium.org303ada72010-10-27 09:33:13 +00006094static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6095
6096
6097// Given a word and two range boundaries returns a word with high bit
6098// set in every byte iff the corresponding input byte was strictly in
6099// the range (m, n). All the other bits in the result are cleared.
6100// This function is only useful when it can be inlined and the
6101// boundaries are statically known.
6102// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006103// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006104static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006105 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006106 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6107 // Use strict inequalities since in edge cases the function could be
6108 // further simplified.
6109 ASSERT(0 < m && m < n && n < 0x7F);
6110 // Has high bit set in every w byte less than n.
6111 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6112 // Has high bit set in every w byte greater than m.
6113 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6114 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6115}
6116
6117
6118enum AsciiCaseConversion {
6119 ASCII_TO_LOWER,
6120 ASCII_TO_UPPER
6121};
6122
6123
6124template <AsciiCaseConversion dir>
6125struct FastAsciiConverter {
6126 static bool Convert(char* dst, char* src, int length) {
6127#ifdef DEBUG
6128 char* saved_dst = dst;
6129 char* saved_src = src;
6130#endif
6131 // We rely on the distance between upper and lower case letters
6132 // being a known power of 2.
6133 ASSERT('a' - 'A' == (1 << 5));
6134 // Boundaries for the range of input characters than require conversion.
6135 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6136 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6137 bool changed = false;
6138 char* const limit = src + length;
6139#ifdef V8_HOST_CAN_READ_UNALIGNED
6140 // Process the prefix of the input that requires no conversion one
6141 // (machine) word at a time.
6142 while (src <= limit - sizeof(uintptr_t)) {
6143 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6144 if (AsciiRangeMask(w, lo, hi) != 0) {
6145 changed = true;
6146 break;
6147 }
6148 *reinterpret_cast<uintptr_t*>(dst) = w;
6149 src += sizeof(uintptr_t);
6150 dst += sizeof(uintptr_t);
6151 }
6152 // Process the remainder of the input performing conversion when
6153 // required one word at a time.
6154 while (src <= limit - sizeof(uintptr_t)) {
6155 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6156 uintptr_t m = AsciiRangeMask(w, lo, hi);
6157 // The mask has high (7th) bit set in every byte that needs
6158 // conversion and we know that the distance between cases is
6159 // 1 << 5.
6160 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6161 src += sizeof(uintptr_t);
6162 dst += sizeof(uintptr_t);
6163 }
6164#endif
6165 // Process the last few bytes of the input (or the whole input if
6166 // unaligned access is not supported).
6167 while (src < limit) {
6168 char c = *src;
6169 if (lo < c && c < hi) {
6170 c ^= (1 << 5);
6171 changed = true;
6172 }
6173 *dst = c;
6174 ++src;
6175 ++dst;
6176 }
6177#ifdef DEBUG
6178 CheckConvert(saved_dst, saved_src, length, changed);
6179#endif
6180 return changed;
6181 }
6182
6183#ifdef DEBUG
6184 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6185 bool expected_changed = false;
6186 for (int i = 0; i < length; i++) {
6187 if (dst[i] == src[i]) continue;
6188 expected_changed = true;
6189 if (dir == ASCII_TO_LOWER) {
6190 ASSERT('A' <= src[i] && src[i] <= 'Z');
6191 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6192 } else {
6193 ASSERT(dir == ASCII_TO_UPPER);
6194 ASSERT('a' <= src[i] && src[i] <= 'z');
6195 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6196 }
6197 }
6198 ASSERT(expected_changed == changed);
6199 }
6200#endif
6201};
6202
6203
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006204struct ToLowerTraits {
6205 typedef unibrow::ToLowercase UnibrowConverter;
6206
lrn@chromium.org303ada72010-10-27 09:33:13 +00006207 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006208};
6209
6210
6211struct ToUpperTraits {
6212 typedef unibrow::ToUppercase UnibrowConverter;
6213
lrn@chromium.org303ada72010-10-27 09:33:13 +00006214 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006215};
6216
6217} // namespace
6218
6219
6220template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006221MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006222 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006223 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006224 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006225 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006226 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006227 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006228
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006229 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006230 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006231 if (length == 0) return s;
6232
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006233 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006234 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006235 // NOTE: This assumes that the upper/lower case of an ASCII
6236 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006237 // might break in the future if we implement more context and locale
6238 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006239 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006240 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006241 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006242 if (!maybe_o->ToObject(&o)) return maybe_o;
6243 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006244 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006245 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006246 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006247 return has_changed_character ? result : s;
6248 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006249
lrn@chromium.org303ada72010-10-27 09:33:13 +00006250 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006251 { MaybeObject* maybe_answer =
6252 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006253 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6254 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006255 if (answer->IsSmi()) {
6256 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006257 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006258 ConvertCaseHelper(isolate,
6259 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006260 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6261 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006262 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006263 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006264}
6265
6266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006267RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006268 return ConvertCase<ToLowerTraits>(
6269 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006270}
6271
6272
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006273RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006274 return ConvertCase<ToUpperTraits>(
6275 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006276}
6277
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006278
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006279static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006280 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006281}
6282
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006284RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006285 NoHandleAllocation ha;
6286 ASSERT(args.length() == 3);
6287
6288 CONVERT_CHECKED(String, s, args[0]);
6289 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6290 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6291
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006292 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006293 int length = s->length();
6294
6295 int left = 0;
6296 if (trimLeft) {
6297 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6298 left++;
6299 }
6300 }
6301
6302 int right = length;
6303 if (trimRight) {
6304 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6305 right--;
6306 }
6307 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006308 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006309}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006310
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006311
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006312RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006313 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006314 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006315 CONVERT_ARG_CHECKED(String, subject, 0);
6316 CONVERT_ARG_CHECKED(String, pattern, 1);
6317 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6318
6319 int subject_length = subject->length();
6320 int pattern_length = pattern->length();
6321 RUNTIME_ASSERT(pattern_length > 0);
6322
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006323 if (limit == 0xffffffffu) {
6324 Handle<Object> cached_answer(StringSplitCache::Lookup(
6325 isolate->heap()->string_split_cache(),
6326 *subject,
6327 *pattern));
6328 if (*cached_answer != Smi::FromInt(0)) {
6329 Handle<JSArray> result =
6330 isolate->factory()->NewJSArrayWithElements(
6331 Handle<FixedArray>::cast(cached_answer));
6332 return *result;
6333 }
6334 }
6335
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006336 // The limit can be very large (0xffffffffu), but since the pattern
6337 // isn't empty, we can never create more parts than ~half the length
6338 // of the subject.
6339
6340 if (!subject->IsFlat()) FlattenString(subject);
6341
6342 static const int kMaxInitialListCapacity = 16;
6343
danno@chromium.org40cb8782011-05-25 07:58:50 +00006344 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006345
6346 // Find (up to limit) indices of separator and end-of-string in subject
6347 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6348 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006349 if (!pattern->IsFlat()) FlattenString(pattern);
6350
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006351 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006352
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006353 if (static_cast<uint32_t>(indices.length()) < limit) {
6354 indices.Add(subject_length);
6355 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006356
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006357 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006358
6359 // Create JSArray of substrings separated by separator.
6360 int part_count = indices.length();
6361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006362 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006363 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006364 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006365 result->set_length(Smi::FromInt(part_count));
6366
6367 ASSERT(result->HasFastElements());
6368
6369 if (part_count == 1 && indices.at(0) == subject_length) {
6370 FixedArray::cast(result->elements())->set(0, *subject);
6371 return *result;
6372 }
6373
6374 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6375 int part_start = 0;
6376 for (int i = 0; i < part_count; i++) {
6377 HandleScope local_loop_handle;
6378 int part_end = indices.at(i);
6379 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006380 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006381 elements->set(i, *substring);
6382 part_start = part_end + pattern_length;
6383 }
6384
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006385 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006386 if (result->HasFastElements()) {
6387 StringSplitCache::Enter(isolate->heap(),
6388 isolate->heap()->string_split_cache(),
6389 *subject,
6390 *pattern,
6391 *elements);
6392 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006393 }
6394
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006395 return *result;
6396}
6397
6398
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006399// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006400// one-char strings in the cache. Gives up on the first char that is
6401// not in the cache and fills the remainder with smi zeros. Returns
6402// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006403static int CopyCachedAsciiCharsToArray(Heap* heap,
6404 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006405 FixedArray* elements,
6406 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006407 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006408 FixedArray* ascii_cache = heap->single_character_string_cache();
6409 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006410 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006411 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006412 for (i = 0; i < length; ++i) {
6413 Object* value = ascii_cache->get(chars[i]);
6414 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006415 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006416 }
6417 if (i < length) {
6418 ASSERT(Smi::FromInt(0) == 0);
6419 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6420 }
6421#ifdef DEBUG
6422 for (int j = 0; j < length; ++j) {
6423 Object* element = elements->get(j);
6424 ASSERT(element == Smi::FromInt(0) ||
6425 (element->IsString() && String::cast(element)->LooksValid()));
6426 }
6427#endif
6428 return i;
6429}
6430
6431
6432// Converts a String to JSArray.
6433// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006434RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006435 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006436 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006437 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006438 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006439
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006440 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006441 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006442
6443 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006444 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006445 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006446 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006447 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006448 { MaybeObject* maybe_obj =
6449 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006450 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6451 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006452 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006453 String::FlatContent content = s->GetFlatContent();
6454 if (content.IsAscii()) {
6455 Vector<const char> chars = content.ToAsciiVector();
6456 // Note, this will initialize all elements (not only the prefix)
6457 // to prevent GC from seeing partially initialized array.
6458 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6459 chars.start(),
6460 *elements,
6461 length);
6462 } else {
6463 MemsetPointer(elements->data_start(),
6464 isolate->heap()->undefined_value(),
6465 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006466 }
6467 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006468 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006469 }
6470 for (int i = position; i < length; ++i) {
6471 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6472 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006473 }
6474
6475#ifdef DEBUG
6476 for (int i = 0; i < length; ++i) {
6477 ASSERT(String::cast(elements->get(i))->length() == 1);
6478 }
6479#endif
6480
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006481 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006482}
6483
6484
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006485RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006486 NoHandleAllocation ha;
6487 ASSERT(args.length() == 1);
6488 CONVERT_CHECKED(String, value, args[0]);
6489 return value->ToObject();
6490}
6491
6492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006493bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006494 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006495 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006496 return char_length == 0;
6497}
6498
6499
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006500RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006501 NoHandleAllocation ha;
6502 ASSERT(args.length() == 1);
6503
6504 Object* number = args[0];
6505 RUNTIME_ASSERT(number->IsNumber());
6506
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006507 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006508}
6509
6510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006511RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006512 NoHandleAllocation ha;
6513 ASSERT(args.length() == 1);
6514
6515 Object* number = args[0];
6516 RUNTIME_ASSERT(number->IsNumber());
6517
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006518 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006519}
6520
6521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006522RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006523 NoHandleAllocation ha;
6524 ASSERT(args.length() == 1);
6525
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006526 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006527
6528 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6529 if (number > 0 && number <= Smi::kMaxValue) {
6530 return Smi::FromInt(static_cast<int>(number));
6531 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006532 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006533}
6534
6535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006536RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006537 NoHandleAllocation ha;
6538 ASSERT(args.length() == 1);
6539
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006540 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006541
6542 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6543 if (number > 0 && number <= Smi::kMaxValue) {
6544 return Smi::FromInt(static_cast<int>(number));
6545 }
6546
6547 double double_value = DoubleToInteger(number);
6548 // Map both -0 and +0 to +0.
6549 if (double_value == 0) double_value = 0;
6550
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006551 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006552}
6553
6554
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006555RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006556 NoHandleAllocation ha;
6557 ASSERT(args.length() == 1);
6558
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006559 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006560 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006561}
6562
6563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006564RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006565 NoHandleAllocation ha;
6566 ASSERT(args.length() == 1);
6567
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006568 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006569
6570 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6571 if (number > 0 && number <= Smi::kMaxValue) {
6572 return Smi::FromInt(static_cast<int>(number));
6573 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006574 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575}
6576
6577
ager@chromium.org870a0b62008-11-04 11:43:05 +00006578// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6579// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006580RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006581 NoHandleAllocation ha;
6582 ASSERT(args.length() == 1);
6583
6584 Object* obj = args[0];
6585 if (obj->IsSmi()) {
6586 return obj;
6587 }
6588 if (obj->IsHeapNumber()) {
6589 double value = HeapNumber::cast(obj)->value();
6590 int int_value = FastD2I(value);
6591 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6592 return Smi::FromInt(int_value);
6593 }
6594 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006595 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006596}
6597
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006598
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006599RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006600 NoHandleAllocation ha;
6601 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006602 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006603}
6604
6605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006606RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006607 NoHandleAllocation ha;
6608 ASSERT(args.length() == 2);
6609
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006610 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6611 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006612 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006613}
6614
6615
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006616RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006617 NoHandleAllocation ha;
6618 ASSERT(args.length() == 2);
6619
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006620 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6621 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006622 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006623}
6624
6625
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006626RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006627 NoHandleAllocation ha;
6628 ASSERT(args.length() == 2);
6629
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006630 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6631 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006632 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006633}
6634
6635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006636RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637 NoHandleAllocation ha;
6638 ASSERT(args.length() == 1);
6639
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006640 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006641 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642}
6643
6644
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006645RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006646 NoHandleAllocation ha;
6647 ASSERT(args.length() == 0);
6648
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006649 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006650}
6651
6652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006653RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006654 NoHandleAllocation ha;
6655 ASSERT(args.length() == 2);
6656
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006657 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6658 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006659 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006660}
6661
6662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006663RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006664 NoHandleAllocation ha;
6665 ASSERT(args.length() == 2);
6666
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006667 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6668 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669
ager@chromium.org3811b432009-10-28 14:53:37 +00006670 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006671 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006672 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006673}
6674
6675
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006676RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677 NoHandleAllocation ha;
6678 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679 CONVERT_CHECKED(String, str1, args[0]);
6680 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006681 isolate->counters()->string_add_runtime()->Increment();
6682 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006683}
6684
6685
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006686template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006687static inline void StringBuilderConcatHelper(String* special,
6688 sinkchar* sink,
6689 FixedArray* fixed_array,
6690 int array_length) {
6691 int position = 0;
6692 for (int i = 0; i < array_length; i++) {
6693 Object* element = fixed_array->get(i);
6694 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006695 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006696 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006697 int pos;
6698 int len;
6699 if (encoded_slice > 0) {
6700 // Position and length encoded in one smi.
6701 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6702 len = StringBuilderSubstringLength::decode(encoded_slice);
6703 } else {
6704 // Position and length encoded in two smis.
6705 Object* obj = fixed_array->get(++i);
6706 ASSERT(obj->IsSmi());
6707 pos = Smi::cast(obj)->value();
6708 len = -encoded_slice;
6709 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006710 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006711 sink + position,
6712 pos,
6713 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006714 position += len;
6715 } else {
6716 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006717 int element_length = string->length();
6718 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006719 position += element_length;
6720 }
6721 }
6722}
6723
6724
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006725RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006726 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006727 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006729 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006730 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006731 return Failure::OutOfMemoryException();
6732 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006733 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006734 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006735
6736 // This assumption is used by the slice encoding in one or two smis.
6737 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6738
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006739 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006740 if (maybe_result->IsFailure()) return maybe_result;
6741
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006742 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006743 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006745 }
6746 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006747 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006748 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006749 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750
6751 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006752 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753 } else if (array_length == 1) {
6754 Object* first = fixed_array->get(0);
6755 if (first->IsString()) return first;
6756 }
6757
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006758 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006759 int position = 0;
6760 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006761 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006762 Object* elt = fixed_array->get(i);
6763 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006764 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006765 int smi_value = Smi::cast(elt)->value();
6766 int pos;
6767 int len;
6768 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006769 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006770 pos = StringBuilderSubstringPosition::decode(smi_value);
6771 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006772 } else {
6773 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006774 len = -smi_value;
6775 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006776 i++;
6777 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006778 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006779 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006780 Object* next_smi = fixed_array->get(i);
6781 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006782 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006783 }
6784 pos = Smi::cast(next_smi)->value();
6785 if (pos < 0) {
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 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006788 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006789 ASSERT(pos >= 0);
6790 ASSERT(len >= 0);
6791 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006792 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006793 }
6794 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795 } else if (elt->IsString()) {
6796 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006797 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006798 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006799 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006801 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006802 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006803 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006804 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006805 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006806 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006807 return Failure::OutOfMemoryException();
6808 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006809 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006810 }
6811
6812 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006813 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006814
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006816 { MaybeObject* maybe_object =
6817 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006818 if (!maybe_object->ToObject(&object)) return maybe_object;
6819 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006820 SeqAsciiString* answer = SeqAsciiString::cast(object);
6821 StringBuilderConcatHelper(special,
6822 answer->GetChars(),
6823 fixed_array,
6824 array_length);
6825 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006826 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006827 { MaybeObject* maybe_object =
6828 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006829 if (!maybe_object->ToObject(&object)) return maybe_object;
6830 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006831 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6832 StringBuilderConcatHelper(special,
6833 answer->GetChars(),
6834 fixed_array,
6835 array_length);
6836 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006837 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006838}
6839
6840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006841RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006842 NoHandleAllocation ha;
6843 ASSERT(args.length() == 3);
6844 CONVERT_CHECKED(JSArray, array, args[0]);
6845 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006846 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006847 return Failure::OutOfMemoryException();
6848 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006849 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006850 CONVERT_CHECKED(String, separator, args[2]);
6851
6852 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006853 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006854 }
6855 FixedArray* fixed_array = FixedArray::cast(array->elements());
6856 if (fixed_array->length() < array_length) {
6857 array_length = fixed_array->length();
6858 }
6859
6860 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006861 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006862 } else if (array_length == 1) {
6863 Object* first = fixed_array->get(0);
6864 if (first->IsString()) return first;
6865 }
6866
6867 int separator_length = separator->length();
6868 int max_nof_separators =
6869 (String::kMaxLength + separator_length - 1) / separator_length;
6870 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006871 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006872 return Failure::OutOfMemoryException();
6873 }
6874 int length = (array_length - 1) * separator_length;
6875 for (int i = 0; i < array_length; i++) {
6876 Object* element_obj = fixed_array->get(i);
6877 if (!element_obj->IsString()) {
6878 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006879 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006880 }
6881 String* element = String::cast(element_obj);
6882 int increment = element->length();
6883 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006884 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006885 return Failure::OutOfMemoryException();
6886 }
6887 length += increment;
6888 }
6889
6890 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006891 { MaybeObject* maybe_object =
6892 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006893 if (!maybe_object->ToObject(&object)) return maybe_object;
6894 }
6895 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6896
6897 uc16* sink = answer->GetChars();
6898#ifdef DEBUG
6899 uc16* end = sink + length;
6900#endif
6901
6902 String* first = String::cast(fixed_array->get(0));
6903 int first_length = first->length();
6904 String::WriteToFlat(first, sink, 0, first_length);
6905 sink += first_length;
6906
6907 for (int i = 1; i < array_length; i++) {
6908 ASSERT(sink + separator_length <= end);
6909 String::WriteToFlat(separator, sink, 0, separator_length);
6910 sink += separator_length;
6911
6912 String* element = String::cast(fixed_array->get(i));
6913 int element_length = element->length();
6914 ASSERT(sink + element_length <= end);
6915 String::WriteToFlat(element, sink, 0, element_length);
6916 sink += element_length;
6917 }
6918 ASSERT(sink == end);
6919
6920 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6921 return answer;
6922}
6923
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006924template <typename Char>
6925static void JoinSparseArrayWithSeparator(FixedArray* elements,
6926 int elements_length,
6927 uint32_t array_length,
6928 String* separator,
6929 Vector<Char> buffer) {
6930 int previous_separator_position = 0;
6931 int separator_length = separator->length();
6932 int cursor = 0;
6933 for (int i = 0; i < elements_length; i += 2) {
6934 int position = NumberToInt32(elements->get(i));
6935 String* string = String::cast(elements->get(i + 1));
6936 int string_length = string->length();
6937 if (string->length() > 0) {
6938 while (previous_separator_position < position) {
6939 String::WriteToFlat<Char>(separator, &buffer[cursor],
6940 0, separator_length);
6941 cursor += separator_length;
6942 previous_separator_position++;
6943 }
6944 String::WriteToFlat<Char>(string, &buffer[cursor],
6945 0, string_length);
6946 cursor += string->length();
6947 }
6948 }
6949 if (separator_length > 0) {
6950 // Array length must be representable as a signed 32-bit number,
6951 // otherwise the total string length would have been too large.
6952 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6953 int last_array_index = static_cast<int>(array_length - 1);
6954 while (previous_separator_position < last_array_index) {
6955 String::WriteToFlat<Char>(separator, &buffer[cursor],
6956 0, separator_length);
6957 cursor += separator_length;
6958 previous_separator_position++;
6959 }
6960 }
6961 ASSERT(cursor <= buffer.length());
6962}
6963
6964
6965RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6966 NoHandleAllocation ha;
6967 ASSERT(args.length() == 3);
6968 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006969 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6970 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006971 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6972 CONVERT_CHECKED(String, separator, args[2]);
6973 // elements_array is fast-mode JSarray of alternating positions
6974 // (increasing order) and strings.
6975 // array_length is length of original array (used to add separators);
6976 // separator is string to put between elements. Assumed to be non-empty.
6977
6978 // Find total length of join result.
6979 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006980 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006981 int max_string_length;
6982 if (is_ascii) {
6983 max_string_length = SeqAsciiString::kMaxLength;
6984 } else {
6985 max_string_length = SeqTwoByteString::kMaxLength;
6986 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006987 bool overflow = false;
6988 CONVERT_NUMBER_CHECKED(int, elements_length,
6989 Int32, elements_array->length());
6990 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6991 FixedArray* elements = FixedArray::cast(elements_array->elements());
6992 for (int i = 0; i < elements_length; i += 2) {
6993 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6994 CONVERT_CHECKED(String, string, elements->get(i + 1));
6995 int length = string->length();
6996 if (is_ascii && !string->IsAsciiRepresentation()) {
6997 is_ascii = false;
6998 max_string_length = SeqTwoByteString::kMaxLength;
6999 }
7000 if (length > max_string_length ||
7001 max_string_length - length < string_length) {
7002 overflow = true;
7003 break;
7004 }
7005 string_length += length;
7006 }
7007 int separator_length = separator->length();
7008 if (!overflow && separator_length > 0) {
7009 if (array_length <= 0x7fffffffu) {
7010 int separator_count = static_cast<int>(array_length) - 1;
7011 int remaining_length = max_string_length - string_length;
7012 if ((remaining_length / separator_length) >= separator_count) {
7013 string_length += separator_length * (array_length - 1);
7014 } else {
7015 // Not room for the separators within the maximal string length.
7016 overflow = true;
7017 }
7018 } else {
7019 // Nonempty separator and at least 2^31-1 separators necessary
7020 // means that the string is too large to create.
7021 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7022 overflow = true;
7023 }
7024 }
7025 if (overflow) {
7026 // Throw OutOfMemory exception for creating too large a string.
7027 V8::FatalProcessOutOfMemory("Array join result too large.");
7028 }
7029
7030 if (is_ascii) {
7031 MaybeObject* result_allocation =
7032 isolate->heap()->AllocateRawAsciiString(string_length);
7033 if (result_allocation->IsFailure()) return result_allocation;
7034 SeqAsciiString* result_string =
7035 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7036 JoinSparseArrayWithSeparator<char>(elements,
7037 elements_length,
7038 array_length,
7039 separator,
7040 Vector<char>(result_string->GetChars(),
7041 string_length));
7042 return result_string;
7043 } else {
7044 MaybeObject* result_allocation =
7045 isolate->heap()->AllocateRawTwoByteString(string_length);
7046 if (result_allocation->IsFailure()) return result_allocation;
7047 SeqTwoByteString* result_string =
7048 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7049 JoinSparseArrayWithSeparator<uc16>(elements,
7050 elements_length,
7051 array_length,
7052 separator,
7053 Vector<uc16>(result_string->GetChars(),
7054 string_length));
7055 return result_string;
7056 }
7057}
7058
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007060RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007061 NoHandleAllocation ha;
7062 ASSERT(args.length() == 2);
7063
7064 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7065 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007066 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007067}
7068
7069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007070RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071 NoHandleAllocation ha;
7072 ASSERT(args.length() == 2);
7073
7074 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7075 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007076 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077}
7078
7079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007080RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007081 NoHandleAllocation ha;
7082 ASSERT(args.length() == 2);
7083
7084 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7085 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007086 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007087}
7088
7089
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007090RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007091 NoHandleAllocation ha;
7092 ASSERT(args.length() == 1);
7093
7094 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007095 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007096}
7097
7098
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007099RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007100 NoHandleAllocation ha;
7101 ASSERT(args.length() == 2);
7102
7103 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7104 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007105 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007106}
7107
7108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007109RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007110 NoHandleAllocation ha;
7111 ASSERT(args.length() == 2);
7112
7113 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7114 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007115 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007116}
7117
7118
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007119RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007120 NoHandleAllocation ha;
7121 ASSERT(args.length() == 2);
7122
7123 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7124 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007125 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007126}
7127
7128
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007129RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007130 NoHandleAllocation ha;
7131 ASSERT(args.length() == 2);
7132
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007133 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7134 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007135 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7136 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7137 if (x == y) return Smi::FromInt(EQUAL);
7138 Object* result;
7139 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7140 result = Smi::FromInt(EQUAL);
7141 } else {
7142 result = Smi::FromInt(NOT_EQUAL);
7143 }
7144 return result;
7145}
7146
7147
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007148RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007149 NoHandleAllocation ha;
7150 ASSERT(args.length() == 2);
7151
7152 CONVERT_CHECKED(String, x, args[0]);
7153 CONVERT_CHECKED(String, y, args[1]);
7154
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007155 bool not_equal = !x->Equals(y);
7156 // This is slightly convoluted because the value that signifies
7157 // equality is 0 and inequality is 1 so we have to negate the result
7158 // from String::Equals.
7159 ASSERT(not_equal == 0 || not_equal == 1);
7160 STATIC_CHECK(EQUAL == 0);
7161 STATIC_CHECK(NOT_EQUAL == 1);
7162 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007163}
7164
7165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007166RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007167 NoHandleAllocation ha;
7168 ASSERT(args.length() == 3);
7169
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007170 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7171 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007172 if (isnan(x) || isnan(y)) return args[2];
7173 if (x == y) return Smi::FromInt(EQUAL);
7174 if (isless(x, y)) return Smi::FromInt(LESS);
7175 return Smi::FromInt(GREATER);
7176}
7177
7178
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007179// Compare two Smis as if they were converted to strings and then
7180// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007181RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007182 NoHandleAllocation ha;
7183 ASSERT(args.length() == 2);
7184
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007185 // Extract the integer values from the Smis.
7186 CONVERT_CHECKED(Smi, x, args[0]);
7187 CONVERT_CHECKED(Smi, y, args[1]);
7188 int x_value = x->value();
7189 int y_value = y->value();
7190
7191 // If the integers are equal so are the string representations.
7192 if (x_value == y_value) return Smi::FromInt(EQUAL);
7193
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007194 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007195 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007196 if (x_value == 0 || y_value == 0)
7197 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007198
ager@chromium.org32912102009-01-16 10:38:43 +00007199 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007200 // smallest because the char code of '-' is less than the char code
7201 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007202
7203 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7204 // architectures using 32-bit Smis.
7205 uint32_t x_scaled = x_value;
7206 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007207 if (x_value < 0 || y_value < 0) {
7208 if (y_value >= 0) return Smi::FromInt(LESS);
7209 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007210 x_scaled = -x_value;
7211 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007212 }
7213
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007214 static const uint32_t kPowersOf10[] = {
7215 1, 10, 100, 1000, 10*1000, 100*1000,
7216 1000*1000, 10*1000*1000, 100*1000*1000,
7217 1000*1000*1000
7218 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007219
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007220 // If the integers have the same number of decimal digits they can be
7221 // compared directly as the numeric order is the same as the
7222 // lexicographic order. If one integer has fewer digits, it is scaled
7223 // by some power of 10 to have the same number of digits as the longer
7224 // integer. If the scaled integers are equal it means the shorter
7225 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007226
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007227 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7228 int x_log2 = IntegerLog2(x_scaled);
7229 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7230 x_log10 -= x_scaled < kPowersOf10[x_log10];
7231
7232 int y_log2 = IntegerLog2(y_scaled);
7233 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7234 y_log10 -= y_scaled < kPowersOf10[y_log10];
7235
7236 int tie = EQUAL;
7237
7238 if (x_log10 < y_log10) {
7239 // X has fewer digits. We would like to simply scale up X but that
7240 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7241 // be scaled up to 9_000_000_000. So we scale up by the next
7242 // smallest power and scale down Y to drop one digit. It is OK to
7243 // drop one digit from the longer integer since the final digit is
7244 // past the length of the shorter integer.
7245 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7246 y_scaled /= 10;
7247 tie = LESS;
7248 } else if (y_log10 < x_log10) {
7249 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7250 x_scaled /= 10;
7251 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007252 }
7253
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007254 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7255 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7256 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007257}
7258
7259
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007260static Object* StringInputBufferCompare(RuntimeState* state,
7261 String* x,
7262 String* y) {
7263 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7264 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007265 bufx.Reset(x);
7266 bufy.Reset(y);
7267 while (bufx.has_more() && bufy.has_more()) {
7268 int d = bufx.GetNext() - bufy.GetNext();
7269 if (d < 0) return Smi::FromInt(LESS);
7270 else if (d > 0) return Smi::FromInt(GREATER);
7271 }
7272
7273 // x is (non-trivial) prefix of y:
7274 if (bufy.has_more()) return Smi::FromInt(LESS);
7275 // y is prefix of x:
7276 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7277}
7278
7279
7280static Object* FlatStringCompare(String* x, String* y) {
7281 ASSERT(x->IsFlat());
7282 ASSERT(y->IsFlat());
7283 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7284 int prefix_length = x->length();
7285 if (y->length() < prefix_length) {
7286 prefix_length = y->length();
7287 equal_prefix_result = Smi::FromInt(GREATER);
7288 } else if (y->length() > prefix_length) {
7289 equal_prefix_result = Smi::FromInt(LESS);
7290 }
7291 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007292 String::FlatContent x_content = x->GetFlatContent();
7293 String::FlatContent y_content = y->GetFlatContent();
7294 if (x_content.IsAscii()) {
7295 Vector<const char> x_chars = x_content.ToAsciiVector();
7296 if (y_content.IsAscii()) {
7297 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007298 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007299 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007300 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007301 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7302 }
7303 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007304 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7305 if (y_content.IsAscii()) {
7306 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007307 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7308 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007309 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007310 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7311 }
7312 }
7313 Object* result;
7314 if (r == 0) {
7315 result = equal_prefix_result;
7316 } else {
7317 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7318 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007319 ASSERT(result ==
7320 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007321 return result;
7322}
7323
7324
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007325RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007326 NoHandleAllocation ha;
7327 ASSERT(args.length() == 2);
7328
7329 CONVERT_CHECKED(String, x, args[0]);
7330 CONVERT_CHECKED(String, y, args[1]);
7331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007332 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007333
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007334 // A few fast case tests before we flatten.
7335 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007336 if (y->length() == 0) {
7337 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007338 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007339 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007340 return Smi::FromInt(LESS);
7341 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007342
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007343 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007344 if (d < 0) return Smi::FromInt(LESS);
7345 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346
lrn@chromium.org303ada72010-10-27 09:33:13 +00007347 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007348 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007349 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7350 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007351 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007352 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7353 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007355 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007356 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007357}
7358
7359
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007360RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007361 NoHandleAllocation ha;
7362 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007363 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007365 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367}
7368
7369
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007370RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371 NoHandleAllocation ha;
7372 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007375 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377}
7378
7379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007380RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381 NoHandleAllocation ha;
7382 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007383 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007385 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387}
7388
7389
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007390static const double kPiDividedBy4 = 0.78539816339744830962;
7391
7392
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007393RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007394 NoHandleAllocation ha;
7395 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007396 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007397
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007398 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7399 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007400 double result;
7401 if (isinf(x) && isinf(y)) {
7402 // Make sure that the result in case of two infinite arguments
7403 // is a multiple of Pi / 4. The sign of the result is determined
7404 // by the first argument (x) and the sign of the second argument
7405 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007406 int multiplier = (x < 0) ? -1 : 1;
7407 if (y < 0) multiplier *= 3;
7408 result = multiplier * kPiDividedBy4;
7409 } else {
7410 result = atan2(x, y);
7411 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007412 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413}
7414
7415
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007416RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007417 NoHandleAllocation ha;
7418 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007419 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007421 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007422 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007423}
7424
7425
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007426RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427 NoHandleAllocation ha;
7428 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007429 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007430
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007431 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007432 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007433}
7434
7435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007436RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007437 NoHandleAllocation ha;
7438 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007439 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007440
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007441 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007442 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007443}
7444
7445
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007446RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447 NoHandleAllocation ha;
7448 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007449 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007450
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007451 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007452 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007453}
7454
7455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007456RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007457 NoHandleAllocation ha;
7458 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007459 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007460
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007461 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007462 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007463}
7464
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007465// Slow version of Math.pow. We check for fast paths for special cases.
7466// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007467RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007468 NoHandleAllocation ha;
7469 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007470 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007471
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007472 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007473
7474 // If the second argument is a smi, it is much faster to call the
7475 // custom powi() function than the generic pow().
7476 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007477 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007478 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007479 }
7480
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007481 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007482 int y_int = static_cast<int>(y);
7483 double result;
7484 if (y == y_int) {
7485 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7486 } else if (y == 0.5) {
7487 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7488 } else if (y == -0.5) {
7489 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7490 } else {
7491 result = power_double_double(x, y);
7492 }
7493 if (isnan(result)) return isolate->heap()->nan_value();
7494 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007495}
7496
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007497// 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 +00007498// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007499RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007500 NoHandleAllocation ha;
7501 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007502 isolate->counters()->math_pow()->Increment();
7503
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007504 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7505 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007506 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007507 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007508 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007509 double result = power_double_double(x, y);
7510 if (isnan(result)) return isolate->heap()->nan_value();
7511 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007512 }
7513}
7514
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007515
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007516RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007517 NoHandleAllocation ha;
7518 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007519 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007520
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007521 if (!args[0]->IsHeapNumber()) {
7522 // Must be smi. Return the argument unchanged for all the other types
7523 // to make fuzz-natives test happy.
7524 return args[0];
7525 }
7526
7527 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7528
7529 double value = number->value();
7530 int exponent = number->get_exponent();
7531 int sign = number->get_sign();
7532
danno@chromium.org160a7b02011-04-18 15:51:38 +00007533 if (exponent < -1) {
7534 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7535 if (sign) return isolate->heap()->minus_zero_value();
7536 return Smi::FromInt(0);
7537 }
7538
7539 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7540 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007541 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007542 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007543 return Smi::FromInt(static_cast<int>(value + 0.5));
7544 }
7545
7546 // If the magnitude is big enough, there's no place for fraction part. If we
7547 // try to add 0.5 to this number, 1.0 will be added instead.
7548 if (exponent >= 52) {
7549 return number;
7550 }
7551
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007552 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007553
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007554 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007555 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007556}
7557
7558
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007559RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007560 NoHandleAllocation ha;
7561 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007562 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007563
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007564 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007565 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007566}
7567
7568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007569RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007570 NoHandleAllocation ha;
7571 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007572 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007573
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007574 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007575 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007576}
7577
7578
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007579RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007580 NoHandleAllocation ha;
7581 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007582 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007583
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007584 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007585 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007586}
7587
7588
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007589static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007590 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7591 181, 212, 243, 273, 304, 334};
7592 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7593 182, 213, 244, 274, 305, 335};
7594
7595 year += month / 12;
7596 month %= 12;
7597 if (month < 0) {
7598 year--;
7599 month += 12;
7600 }
7601
7602 ASSERT(month >= 0);
7603 ASSERT(month < 12);
7604
7605 // year_delta is an arbitrary number such that:
7606 // a) year_delta = -1 (mod 400)
7607 // b) year + year_delta > 0 for years in the range defined by
7608 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7609 // Jan 1 1970. This is required so that we don't run into integer
7610 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007611 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007612 // operations.
7613 static const int year_delta = 399999;
7614 static const int base_day = 365 * (1970 + year_delta) +
7615 (1970 + year_delta) / 4 -
7616 (1970 + year_delta) / 100 +
7617 (1970 + year_delta) / 400;
7618
7619 int year1 = year + year_delta;
7620 int day_from_year = 365 * year1 +
7621 year1 / 4 -
7622 year1 / 100 +
7623 year1 / 400 -
7624 base_day;
7625
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007626 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7627 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007628 }
7629
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007630 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007631}
7632
7633
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007634RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007635 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007636 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007637
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007638 CONVERT_SMI_ARG_CHECKED(year, 0);
7639 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007640
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007641 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007642}
7643
7644
7645static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7646static const int kDaysIn4Years = 4 * 365 + 1;
7647static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7648static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7649static const int kDays1970to2000 = 30 * 365 + 7;
7650static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7651 kDays1970to2000;
7652static const int kYearsOffset = 400000;
7653
7654static const char kDayInYear[] = {
7655 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7656 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7657 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7658 22, 23, 24, 25, 26, 27, 28,
7659 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7660 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7661 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7662 22, 23, 24, 25, 26, 27, 28, 29, 30,
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, 29, 30,
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, 31,
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,
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, 31,
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,
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
7680 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7681 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7682 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7683 22, 23, 24, 25, 26, 27, 28,
7684 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7685 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7686 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7687 22, 23, 24, 25, 26, 27, 28, 29, 30,
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, 29, 30,
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, 31,
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,
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, 31,
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,
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
7705 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7706 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7707 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7708 22, 23, 24, 25, 26, 27, 28, 29,
7709 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7710 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7711 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7712 22, 23, 24, 25, 26, 27, 28, 29, 30,
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, 30,
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, 31,
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,
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, 31,
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,
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
7730 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7731 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7732 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7733 22, 23, 24, 25, 26, 27, 28,
7734 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7735 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7736 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7737 22, 23, 24, 25, 26, 27, 28, 29, 30,
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, 29, 30,
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, 31,
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,
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, 31,
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,
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
7755static const char kMonthInYear[] = {
7756 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,
7757 0, 0, 0, 0, 0, 0,
7758 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,
7759 1, 1, 1,
7760 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,
7761 2, 2, 2, 2, 2, 2,
7762 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,
7763 3, 3, 3, 3, 3,
7764 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,
7765 4, 4, 4, 4, 4, 4,
7766 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,
7767 5, 5, 5, 5, 5,
7768 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,
7769 6, 6, 6, 6, 6, 6,
7770 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,
7771 7, 7, 7, 7, 7, 7,
7772 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,
7773 8, 8, 8, 8, 8,
7774 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,
7775 9, 9, 9, 9, 9, 9,
7776 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7777 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7778 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7779 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7780
7781 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,
7782 0, 0, 0, 0, 0, 0,
7783 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,
7784 1, 1, 1,
7785 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,
7786 2, 2, 2, 2, 2, 2,
7787 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,
7788 3, 3, 3, 3, 3,
7789 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,
7790 4, 4, 4, 4, 4, 4,
7791 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,
7792 5, 5, 5, 5, 5,
7793 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,
7794 6, 6, 6, 6, 6, 6,
7795 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,
7796 7, 7, 7, 7, 7, 7,
7797 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,
7798 8, 8, 8, 8, 8,
7799 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,
7800 9, 9, 9, 9, 9, 9,
7801 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7802 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7803 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7804 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7805
7806 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,
7807 0, 0, 0, 0, 0, 0,
7808 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,
7809 1, 1, 1, 1,
7810 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,
7811 2, 2, 2, 2, 2, 2,
7812 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,
7813 3, 3, 3, 3, 3,
7814 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,
7815 4, 4, 4, 4, 4, 4,
7816 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,
7817 5, 5, 5, 5, 5,
7818 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,
7819 6, 6, 6, 6, 6, 6,
7820 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,
7821 7, 7, 7, 7, 7, 7,
7822 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,
7823 8, 8, 8, 8, 8,
7824 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,
7825 9, 9, 9, 9, 9, 9,
7826 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7827 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7828 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7829 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7830
7831 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,
7832 0, 0, 0, 0, 0, 0,
7833 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,
7834 1, 1, 1,
7835 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,
7836 2, 2, 2, 2, 2, 2,
7837 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,
7838 3, 3, 3, 3, 3,
7839 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,
7840 4, 4, 4, 4, 4, 4,
7841 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,
7842 5, 5, 5, 5, 5,
7843 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,
7844 6, 6, 6, 6, 6, 6,
7845 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,
7846 7, 7, 7, 7, 7, 7,
7847 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,
7848 8, 8, 8, 8, 8,
7849 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,
7850 9, 9, 9, 9, 9, 9,
7851 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7852 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7853 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7854 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7855
7856
7857// This function works for dates from 1970 to 2099.
7858static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007859 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007860#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007861 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007862#endif
7863
7864 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7865 date %= kDaysIn4Years;
7866
7867 month = kMonthInYear[date];
7868 day = kDayInYear[date];
7869
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007870 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007871}
7872
7873
7874static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007875 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007876#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007877 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007878#endif
7879
7880 date += kDaysOffset;
7881 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7882 date %= kDaysIn400Years;
7883
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007884 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007885
7886 date--;
7887 int yd1 = date / kDaysIn100Years;
7888 date %= kDaysIn100Years;
7889 year += 100 * yd1;
7890
7891 date++;
7892 int yd2 = date / kDaysIn4Years;
7893 date %= kDaysIn4Years;
7894 year += 4 * yd2;
7895
7896 date--;
7897 int yd3 = date / 365;
7898 date %= 365;
7899 year += yd3;
7900
7901 bool is_leap = (!yd1 || yd2) && !yd3;
7902
7903 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007904 ASSERT(is_leap || (date >= 0));
7905 ASSERT((date < 365) || (is_leap && (date < 366)));
7906 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007907 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7908 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007909
7910 if (is_leap) {
7911 day = kDayInYear[2*365 + 1 + date];
7912 month = kMonthInYear[2*365 + 1 + date];
7913 } else {
7914 day = kDayInYear[date];
7915 month = kMonthInYear[date];
7916 }
7917
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007918 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007919}
7920
7921
7922static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007923 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007924 if (date >= 0 && date < 32 * kDaysIn4Years) {
7925 DateYMDFromTimeAfter1970(date, year, month, day);
7926 } else {
7927 DateYMDFromTimeSlow(date, year, month, day);
7928 }
7929}
7930
7931
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007932RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007933 NoHandleAllocation ha;
7934 ASSERT(args.length() == 2);
7935
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007936 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007937 CONVERT_CHECKED(JSArray, res_array, args[1]);
7938
7939 int year, month, day;
7940 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7941
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007942 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7943 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007944 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007945
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007946 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7947 if (maybe->IsFailure()) return maybe;
7948 FixedArray* elms = FixedArray::cast(res_array->elements());
7949 elms->set(0, Smi::FromInt(year));
7950 elms->set(1, Smi::FromInt(month));
7951 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007952
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007953 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007954}
7955
7956
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007957RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007958 HandleScope scope(isolate);
7959 ASSERT(args.length() == 3);
7960
7961 Handle<JSFunction> callee = args.at<JSFunction>(0);
7962 Object** parameters = reinterpret_cast<Object**>(args[1]);
7963 const int argument_count = Smi::cast(args[2])->value();
7964
7965 Handle<JSObject> result =
7966 isolate->factory()->NewArgumentsObject(callee, argument_count);
7967 // Allocate the elements if needed.
7968 int parameter_count = callee->shared()->formal_parameter_count();
7969 if (argument_count > 0) {
7970 if (parameter_count > 0) {
7971 int mapped_count = Min(argument_count, parameter_count);
7972 Handle<FixedArray> parameter_map =
7973 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7974 parameter_map->set_map(
7975 isolate->heap()->non_strict_arguments_elements_map());
7976
7977 Handle<Map> old_map(result->map());
7978 Handle<Map> new_map =
7979 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007980 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007981
7982 result->set_map(*new_map);
7983 result->set_elements(*parameter_map);
7984
7985 // Store the context and the arguments array at the beginning of the
7986 // parameter map.
7987 Handle<Context> context(isolate->context());
7988 Handle<FixedArray> arguments =
7989 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7990 parameter_map->set(0, *context);
7991 parameter_map->set(1, *arguments);
7992
7993 // Loop over the actual parameters backwards.
7994 int index = argument_count - 1;
7995 while (index >= mapped_count) {
7996 // These go directly in the arguments array and have no
7997 // corresponding slot in the parameter map.
7998 arguments->set(index, *(parameters - index - 1));
7999 --index;
8000 }
8001
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008002 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00008003 while (index >= 0) {
8004 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008005 Handle<String> name(scope_info->ParameterName(index));
8006 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00008007 bool duplicate = false;
8008 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008009 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008010 duplicate = true;
8011 break;
8012 }
8013 }
8014
8015 if (duplicate) {
8016 // This goes directly in the arguments array with a hole in the
8017 // parameter map.
8018 arguments->set(index, *(parameters - index - 1));
8019 parameter_map->set_the_hole(index + 2);
8020 } else {
8021 // The context index goes in the parameter map with a hole in the
8022 // arguments array.
8023 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008024 for (int j = 0; j < context_local_count; ++j) {
8025 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008026 context_index = j;
8027 break;
8028 }
8029 }
8030 ASSERT(context_index >= 0);
8031 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008032 parameter_map->set(index + 2, Smi::FromInt(
8033 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00008034 }
8035
8036 --index;
8037 }
8038 } else {
8039 // If there is no aliasing, the arguments object elements are not
8040 // special in any way.
8041 Handle<FixedArray> elements =
8042 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8043 result->set_elements(*elements);
8044 for (int i = 0; i < argument_count; ++i) {
8045 elements->set(i, *(parameters - i - 1));
8046 }
8047 }
8048 }
8049 return *result;
8050}
8051
8052
8053RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008054 NoHandleAllocation ha;
8055 ASSERT(args.length() == 3);
8056
8057 JSFunction* callee = JSFunction::cast(args[0]);
8058 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008059 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008060
lrn@chromium.org303ada72010-10-27 09:33:13 +00008061 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008062 { MaybeObject* maybe_result =
8063 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008064 if (!maybe_result->ToObject(&result)) return maybe_result;
8065 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008066 // Allocate the elements if needed.
8067 if (length > 0) {
8068 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008069 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008070 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008071 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8072 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008073
8074 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008075 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008076 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008077 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008078
8079 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008080 for (int i = 0; i < length; i++) {
8081 array->set(i, *--parameters, mode);
8082 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008083 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008084 }
8085 return result;
8086}
8087
8088
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008089RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008090 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008091 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008092 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008093 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008094 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008095
whesse@chromium.org7b260152011-06-20 15:33:18 +00008096 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008097 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008098 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008099 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008100 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8101 context,
8102 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008103 return *result;
8104}
8105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008106
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008107// Find the arguments of the JavaScript function invocation that called
8108// into C++ code. Collect these in a newly allocated array of handles (possibly
8109// prefixed by a number of empty handles).
8110static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8111 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008112 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008113 // Find frame containing arguments passed to the caller.
8114 JavaScriptFrameIterator it;
8115 JavaScriptFrame* frame = it.frame();
8116 List<JSFunction*> functions(2);
8117 frame->GetFunctions(&functions);
8118 if (functions.length() > 1) {
8119 int inlined_frame_index = functions.length() - 1;
8120 JSFunction* inlined_function = functions[inlined_frame_index];
8121 int args_count = inlined_function->shared()->formal_parameter_count();
8122 ScopedVector<SlotRef> args_slots(args_count);
8123 SlotRef::ComputeSlotMappingForArguments(frame,
8124 inlined_frame_index,
8125 &args_slots);
8126
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008127 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008128 SmartArrayPointer<Handle<Object> > param_data(
8129 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008130 for (int i = 0; i < args_count; i++) {
8131 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008132 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008133 }
8134 return param_data;
8135 } else {
8136 it.AdvanceToArgumentsFrame();
8137 frame = it.frame();
8138 int args_count = frame->ComputeParametersCount();
8139
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008140 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008141 SmartArrayPointer<Handle<Object> > param_data(
8142 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008143 for (int i = 0; i < args_count; i++) {
8144 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008145 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008146 }
8147 return param_data;
8148 }
8149}
8150
8151
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008152RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8153 HandleScope scope(isolate);
8154 ASSERT(args.length() == 4);
8155 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8156 RUNTIME_ASSERT(args[3]->IsNumber());
8157 Handle<Object> bindee = args.at<Object>(1);
8158
8159 // TODO(lrn): Create bound function in C++ code from premade shared info.
8160 bound_function->shared()->set_bound(true);
8161 // Get all arguments of calling function (Function.prototype.bind).
8162 int argc = 0;
8163 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8164 // Don't count the this-arg.
8165 if (argc > 0) {
8166 ASSERT(*arguments[0] == args[2]);
8167 argc--;
8168 } else {
8169 ASSERT(args[2]->IsUndefined());
8170 }
8171 // Initialize array of bindings (function, this, and any existing arguments
8172 // if the function was already bound).
8173 Handle<FixedArray> new_bindings;
8174 int i;
8175 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8176 Handle<FixedArray> old_bindings(
8177 JSFunction::cast(*bindee)->function_bindings());
8178 new_bindings =
8179 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8180 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8181 i = 0;
8182 for (int n = old_bindings->length(); i < n; i++) {
8183 new_bindings->set(i, old_bindings->get(i));
8184 }
8185 } else {
8186 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8187 new_bindings = isolate->factory()->NewFixedArray(array_size);
8188 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8189 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8190 i = 2;
8191 }
8192 // Copy arguments, skipping the first which is "this_arg".
8193 for (int j = 0; j < argc; j++, i++) {
8194 new_bindings->set(i, *arguments[j + 1]);
8195 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008196 new_bindings->set_map_no_write_barrier(
8197 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008198 bound_function->set_function_bindings(*new_bindings);
8199
8200 // Update length.
8201 Handle<String> length_symbol = isolate->factory()->length_symbol();
8202 Handle<Object> new_length(args.at<Object>(3));
8203 PropertyAttributes attr =
8204 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8205 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8206 return *bound_function;
8207}
8208
8209
8210RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8211 HandleScope handles(isolate);
8212 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008213 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008214 if (callable->IsJSFunction()) {
8215 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8216 if (function->shared()->bound()) {
8217 Handle<FixedArray> bindings(function->function_bindings());
8218 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8219 return *isolate->factory()->NewJSArrayWithElements(bindings);
8220 }
8221 }
8222 return isolate->heap()->undefined_value();
8223}
8224
8225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008226RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008227 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008228 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008229 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008230 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008231 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008232
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008233 // The argument is a bound function. Extract its bound arguments
8234 // and callable.
8235 Handle<FixedArray> bound_args =
8236 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8237 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8238 Handle<Object> bound_function(
8239 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8240 ASSERT(!bound_function->IsJSFunction() ||
8241 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008242
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008243 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008244 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008245 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008246 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008247 param_data[i] = Handle<Object>(bound_args->get(
8248 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008249 }
8250
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008251 if (!bound_function->IsJSFunction()) {
8252 bool exception_thrown;
8253 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8254 &exception_thrown);
8255 if (exception_thrown) return Failure::Exception();
8256 }
8257 ASSERT(bound_function->IsJSFunction());
8258
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008259 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008260 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008261 Execution::New(Handle<JSFunction>::cast(bound_function),
8262 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008263 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008264 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008265 }
8266 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008267 return *result;
8268}
8269
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008270
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008271static void TrySettingInlineConstructStub(Isolate* isolate,
8272 Handle<JSFunction> function) {
8273 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008274 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008275 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008276 }
8277 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008278 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008279 Handle<Code> code = compiler.CompileConstructStub(function);
8280 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008281 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008282}
8283
8284
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008285RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008286 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008287 ASSERT(args.length() == 1);
8288
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008289 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008290
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008291 // If the constructor isn't a proper function we throw a type error.
8292 if (!constructor->IsJSFunction()) {
8293 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8294 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008295 isolate->factory()->NewTypeError("not_constructor", arguments);
8296 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008297 }
8298
8299 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008300
8301 // If function should not have prototype, construction is not allowed. In this
8302 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008303 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008304 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8305 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008306 isolate->factory()->NewTypeError("not_constructor", arguments);
8307 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008308 }
8309
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008310#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008311 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008312 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008313 if (debug->StepInActive()) {
8314 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008315 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008316#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008317
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008318 if (function->has_initial_map()) {
8319 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008320 // The 'Function' function ignores the receiver object when
8321 // called using 'new' and creates a new JSFunction object that
8322 // is returned. The receiver object is only used for error
8323 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008324 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008325 // allocate JSFunctions since it does not properly initialize
8326 // the shared part of the function. Since the receiver is
8327 // ignored anyway, we use the global object as the receiver
8328 // instead of a new JSFunction object. This way, errors are
8329 // reported the same way whether or not 'Function' is called
8330 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008331 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008332 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008333 }
8334
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008335 // The function should be compiled for the optimization hints to be
8336 // available. We cannot use EnsureCompiled because that forces a
8337 // compilation through the shared function info which makes it
8338 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008339 if (!function->is_compiled()) {
8340 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8341 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008342
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008343 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008344 if (!function->has_initial_map() &&
8345 shared->IsInobjectSlackTrackingInProgress()) {
8346 // The tracking is already in progress for another function. We can only
8347 // track one initial_map at a time, so we force the completion before the
8348 // function is called as a constructor for the first time.
8349 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008350 }
8351
8352 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008353 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8354 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008355 // Delay setting the stub if inobject slack tracking is in progress.
8356 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008357 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008358 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008360 isolate->counters()->constructed_objects()->Increment();
8361 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008362
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008363 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008364}
8365
8366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008367RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008368 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008369 ASSERT(args.length() == 1);
8370
8371 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8372 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008373 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008374
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008375 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008376}
8377
8378
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008379RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008380 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008381 ASSERT(args.length() == 1);
8382
8383 Handle<JSFunction> function = args.at<JSFunction>(0);
8384#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008385 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008386 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008387 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008388 PrintF("]\n");
8389 }
8390#endif
8391
lrn@chromium.org34e60782011-09-15 07:25:40 +00008392 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008393 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008394 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008395 return Failure::Exception();
8396 }
8397
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008398 // All done. Return the compiled code.
8399 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008400 return function->code();
8401}
8402
8403
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008404RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008405 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008406 ASSERT(args.length() == 1);
8407 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008408
8409 // If the function is not compiled ignore the lazy
8410 // recompilation. This can happen if the debugger is activated and
8411 // the function is returned to the not compiled state.
8412 if (!function->shared()->is_compiled()) {
8413 function->ReplaceCode(function->shared()->code());
8414 return function->code();
8415 }
8416
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008417 // If the function is not optimizable or debugger is active continue using the
8418 // code from the full compiler.
8419 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008420 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008421 if (FLAG_trace_opt) {
8422 PrintF("[failed to optimize ");
8423 function->PrintName();
8424 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8425 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008426 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008427 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008428 function->ReplaceCode(function->shared()->code());
8429 return function->code();
8430 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008431 if (JSFunction::CompileOptimized(function,
8432 AstNode::kNoNumber,
8433 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008434 return function->code();
8435 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008436 if (FLAG_trace_opt) {
8437 PrintF("[failed to optimize ");
8438 function->PrintName();
8439 PrintF(": optimized compilation failed]\n");
8440 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008441 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008442 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008443}
8444
8445
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008446class ActivationsFinder : public ThreadVisitor {
8447 public:
8448 explicit ActivationsFinder(JSFunction* function)
8449 : function_(function), has_activations_(false) {}
8450
8451 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8452 if (has_activations_) return;
8453
8454 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8455 JavaScriptFrame* frame = it.frame();
8456 if (frame->is_optimized() && frame->function() == function_) {
8457 has_activations_ = true;
8458 return;
8459 }
8460 }
8461 }
8462
8463 bool has_activations() { return has_activations_; }
8464
8465 private:
8466 JSFunction* function_;
8467 bool has_activations_;
8468};
8469
8470
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008471RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008472 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008473 ASSERT(args.length() == 1);
8474 RUNTIME_ASSERT(args[0]->IsSmi());
8475 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008476 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008477 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8478 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008479 int frames = deoptimizer->output_count();
8480
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008481 deoptimizer->MaterializeHeapNumbers();
8482 delete deoptimizer;
8483
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008484 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008485 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008486 for (int i = 0; i < frames - 1; i++) it.Advance();
8487 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008488
8489 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008491 Handle<Object> arguments;
8492 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008493 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008494 if (arguments.is_null()) {
8495 // FunctionGetArguments can't throw an exception, so cast away the
8496 // doubt with an assert.
8497 arguments = Handle<Object>(
8498 Accessors::FunctionGetArguments(*function,
8499 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008500 ASSERT(*arguments != isolate->heap()->null_value());
8501 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008502 }
8503 frame->SetExpression(i, *arguments);
8504 }
8505 }
8506
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008507 if (type == Deoptimizer::EAGER) {
8508 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008509 }
8510
8511 // Avoid doing too much work when running with --always-opt and keep
8512 // the optimized code around.
8513 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008514 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008515 }
8516
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008517 // Find other optimized activations of the function.
8518 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008519 while (!it.done()) {
8520 JavaScriptFrame* frame = it.frame();
8521 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008522 has_other_activations = true;
8523 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008524 }
8525 it.Advance();
8526 }
8527
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008528 if (!has_other_activations) {
8529 ActivationsFinder activations_finder(*function);
8530 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8531 has_other_activations = activations_finder.has_activations();
8532 }
8533
8534 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008535 if (FLAG_trace_deopt) {
8536 PrintF("[removing optimized code for: ");
8537 function->PrintName();
8538 PrintF("]\n");
8539 }
8540 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008541 } else {
8542 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008544 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008545}
8546
8547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008548RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008549 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008550 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008551 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008552}
8553
8554
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008555RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008556 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008557 ASSERT(args.length() == 1);
8558 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008559 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008560
8561 Deoptimizer::DeoptimizeFunction(*function);
8562
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008563 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008564}
8565
8566
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008567RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8568#if defined(USE_SIMULATOR)
8569 return isolate->heap()->true_value();
8570#else
8571 return isolate->heap()->false_value();
8572#endif
8573}
8574
8575
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008576RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8577 HandleScope scope(isolate);
8578 ASSERT(args.length() == 1);
8579 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8580 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8581 function->MarkForLazyRecompilation();
8582 return isolate->heap()->undefined_value();
8583}
8584
8585
lrn@chromium.org1c092762011-05-09 09:42:16 +00008586RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8587 HandleScope scope(isolate);
8588 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008589 // The least significant bit (after untagging) indicates whether the
8590 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008591 if (!V8::UseCrankshaft()) {
8592 return Smi::FromInt(4); // 4 == "never".
8593 }
8594 if (FLAG_always_opt) {
8595 return Smi::FromInt(3); // 3 == "always".
8596 }
8597 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8598 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8599 : Smi::FromInt(2); // 2 == "no".
8600}
8601
8602
8603RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8604 HandleScope scope(isolate);
8605 ASSERT(args.length() == 1);
8606 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8607 return Smi::FromInt(function->shared()->opt_count());
8608}
8609
8610
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008611RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008612 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008613 ASSERT(args.length() == 1);
8614 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8615
8616 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008617 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008618
8619 // We have hit a back edge in an unoptimized frame for a function that was
8620 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008621 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008622 // Keep track of whether we've succeeded in optimizing.
8623 bool succeeded = unoptimized->optimizable();
8624 if (succeeded) {
8625 // If we are trying to do OSR when there are already optimized
8626 // activations of the function, it means (a) the function is directly or
8627 // indirectly recursive and (b) an optimized invocation has been
8628 // deoptimized so that we are currently in an unoptimized activation.
8629 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008630 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008631 while (succeeded && !it.done()) {
8632 JavaScriptFrame* frame = it.frame();
8633 succeeded = !frame->is_optimized() || frame->function() != *function;
8634 it.Advance();
8635 }
8636 }
8637
8638 int ast_id = AstNode::kNoNumber;
8639 if (succeeded) {
8640 // The top JS function is this one, the PC is somewhere in the
8641 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008642 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008643 JavaScriptFrame* frame = it.frame();
8644 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008645 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008646 ASSERT(unoptimized->contains(frame->pc()));
8647
8648 // Use linear search of the unoptimized code's stack check table to find
8649 // the AST id matching the PC.
8650 Address start = unoptimized->instruction_start();
8651 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008652 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008653 uint32_t table_length = Memory::uint32_at(table_cursor);
8654 table_cursor += kIntSize;
8655 for (unsigned i = 0; i < table_length; ++i) {
8656 // Table entries are (AST id, pc offset) pairs.
8657 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8658 if (pc_offset == target_pc_offset) {
8659 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8660 break;
8661 }
8662 table_cursor += 2 * kIntSize;
8663 }
8664 ASSERT(ast_id != AstNode::kNoNumber);
8665 if (FLAG_trace_osr) {
8666 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8667 function->PrintName();
8668 PrintF("]\n");
8669 }
8670
8671 // Try to compile the optimized code. A true return value from
8672 // CompileOptimized means that compilation succeeded, not necessarily
8673 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008674 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008675 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008676 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8677 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008678 if (data->OsrPcOffset()->value() >= 0) {
8679 if (FLAG_trace_osr) {
8680 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008681 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008682 }
8683 ASSERT(data->OsrAstId()->value() == ast_id);
8684 } else {
8685 // We may never generate the desired OSR entry if we emit an
8686 // early deoptimize.
8687 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008688 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008689 } else {
8690 succeeded = false;
8691 }
8692 }
8693
8694 // Revert to the original stack checks in the original unoptimized code.
8695 if (FLAG_trace_osr) {
8696 PrintF("[restoring original stack checks in ");
8697 function->PrintName();
8698 PrintF("]\n");
8699 }
8700 StackCheckStub check_stub;
8701 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008702 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008703 Deoptimizer::RevertStackCheckCode(*unoptimized,
8704 *check_code,
8705 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008706
8707 // Allow OSR only at nesting level zero again.
8708 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8709
8710 // If the optimization attempt succeeded, return the AST id tagged as a
8711 // smi. This tells the builtin that we need to translate the unoptimized
8712 // frame to an optimized one.
8713 if (succeeded) {
8714 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8715 return Smi::FromInt(ast_id);
8716 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008717 if (function->IsMarkedForLazyRecompilation()) {
8718 function->ReplaceCode(function->shared()->code());
8719 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008720 return Smi::FromInt(-1);
8721 }
8722}
8723
8724
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008725RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8726 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8727 return isolate->heap()->undefined_value();
8728}
8729
8730
danno@chromium.orgc612e022011-11-10 11:38:15 +00008731RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8732 HandleScope scope(isolate);
8733 ASSERT(args.length() >= 2);
8734 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8735 Object* receiver = args[0];
8736 int argc = args.length() - 2;
8737
8738 // If there are too many arguments, allocate argv via malloc.
8739 const int argv_small_size = 10;
8740 Handle<Object> argv_small_buffer[argv_small_size];
8741 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8742 Handle<Object>* argv = argv_small_buffer;
8743 if (argc > argv_small_size) {
8744 argv = new Handle<Object>[argc];
8745 if (argv == NULL) return isolate->StackOverflow();
8746 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8747 }
8748
8749 for (int i = 0; i < argc; ++i) {
8750 MaybeObject* maybe = args[1 + i];
8751 Object* object;
8752 if (!maybe->To<Object>(&object)) return maybe;
8753 argv[i] = Handle<Object>(object);
8754 }
8755
8756 bool threw;
8757 Handle<JSReceiver> hfun(fun);
8758 Handle<Object> hreceiver(receiver);
8759 Handle<Object> result =
8760 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8761
8762 if (threw) return Failure::Exception();
8763 return *result;
8764}
8765
8766
lrn@chromium.org34e60782011-09-15 07:25:40 +00008767RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8768 HandleScope scope(isolate);
8769 ASSERT(args.length() == 5);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008770 CONVERT_ARG_CHECKED(JSReceiver, fun, 0);
8771 Handle<Object> receiver = args.at<Object>(1);
8772 CONVERT_ARG_CHECKED(JSObject, arguments, 2);
8773 CONVERT_SMI_ARG_CHECKED(offset, 3);
8774 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008775 ASSERT(offset >= 0);
8776 ASSERT(argc >= 0);
8777
8778 // If there are too many arguments, allocate argv via malloc.
8779 const int argv_small_size = 10;
8780 Handle<Object> argv_small_buffer[argv_small_size];
8781 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8782 Handle<Object>* argv = argv_small_buffer;
8783 if (argc > argv_small_size) {
8784 argv = new Handle<Object>[argc];
8785 if (argv == NULL) return isolate->StackOverflow();
8786 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8787 }
8788
8789 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008790 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008791 }
8792
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008793 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008794 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008795 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008796
8797 if (threw) return Failure::Exception();
8798 return *result;
8799}
8800
8801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008802RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008803 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008804 ASSERT(args.length() == 1);
8805 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8806 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8807}
8808
8809
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008810RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008811 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008812 ASSERT(args.length() == 1);
8813 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8814 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8815}
8816
8817
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008818RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008819 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008820 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008821
kasper.lund7276f142008-07-30 08:49:36 +00008822 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008823 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008824 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008825 { MaybeObject* maybe_result =
8826 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008827 if (!maybe_result->ToObject(&result)) return maybe_result;
8828 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008829
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008830 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008831
kasper.lund7276f142008-07-30 08:49:36 +00008832 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008833}
8834
lrn@chromium.org303ada72010-10-27 09:33:13 +00008835
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008836RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8837 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008838 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008839 JSObject* extension_object;
8840 if (args[0]->IsJSObject()) {
8841 extension_object = JSObject::cast(args[0]);
8842 } else {
8843 // Convert the object to a proper JavaScript object.
8844 MaybeObject* maybe_js_object = args[0]->ToObject();
8845 if (!maybe_js_object->To(&extension_object)) {
8846 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8847 HandleScope scope(isolate);
8848 Handle<Object> handle = args.at<Object>(0);
8849 Handle<Object> result =
8850 isolate->factory()->NewTypeError("with_expression",
8851 HandleVector(&handle, 1));
8852 return isolate->Throw(*result);
8853 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008854 return maybe_js_object;
8855 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008856 }
8857 }
8858
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008859 JSFunction* function;
8860 if (args[1]->IsSmi()) {
8861 // A smi sentinel indicates a context nested inside global code rather
8862 // than some function. There is a canonical empty function that can be
8863 // gotten from the global context.
8864 function = isolate->context()->global_context()->closure();
8865 } else {
8866 function = JSFunction::cast(args[1]);
8867 }
8868
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008869 Context* context;
8870 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008871 isolate->heap()->AllocateWithContext(function,
8872 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008873 extension_object);
8874 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008875 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008876 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008877}
8878
8879
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008880RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008881 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008882 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008883 String* name = String::cast(args[0]);
8884 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008885 JSFunction* function;
8886 if (args[2]->IsSmi()) {
8887 // A smi sentinel indicates a context nested inside global code rather
8888 // than some function. There is a canonical empty function that can be
8889 // gotten from the global context.
8890 function = isolate->context()->global_context()->closure();
8891 } else {
8892 function = JSFunction::cast(args[2]);
8893 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008894 Context* context;
8895 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008896 isolate->heap()->AllocateCatchContext(function,
8897 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008898 name,
8899 thrown_object);
8900 if (!maybe_context->To(&context)) return maybe_context;
8901 isolate->set_context(context);
8902 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008903}
8904
8905
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008906RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8907 NoHandleAllocation ha;
8908 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008909 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008910 JSFunction* function;
8911 if (args[1]->IsSmi()) {
8912 // A smi sentinel indicates a context nested inside global code rather
8913 // than some function. There is a canonical empty function that can be
8914 // gotten from the global context.
8915 function = isolate->context()->global_context()->closure();
8916 } else {
8917 function = JSFunction::cast(args[1]);
8918 }
8919 Context* context;
8920 MaybeObject* maybe_context =
8921 isolate->heap()->AllocateBlockContext(function,
8922 isolate->context(),
8923 scope_info);
8924 if (!maybe_context->To(&context)) return maybe_context;
8925 isolate->set_context(context);
8926 return context;
8927}
8928
8929
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008930RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008931 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008932 ASSERT(args.length() == 2);
8933
8934 CONVERT_ARG_CHECKED(Context, context, 0);
8935 CONVERT_ARG_CHECKED(String, name, 1);
8936
8937 int index;
8938 PropertyAttributes attributes;
8939 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008940 BindingFlags binding_flags;
8941 Handle<Object> holder = context->Lookup(name,
8942 flags,
8943 &index,
8944 &attributes,
8945 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008946
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008947 // If the slot was not found the result is true.
8948 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008949 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008950 }
8951
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008952 // If the slot was found in a context, it should be DONT_DELETE.
8953 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008954 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008955 }
8956
8957 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008958 // the global object, or the subject of a with. Try to delete it
8959 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008960 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008961 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008962}
8963
8964
ager@chromium.orga1645e22009-09-09 19:27:10 +00008965// A mechanism to return a pair of Object pointers in registers (if possible).
8966// How this is achieved is calling convention-dependent.
8967// All currently supported x86 compiles uses calling conventions that are cdecl
8968// variants where a 64-bit value is returned in two 32-bit registers
8969// (edx:eax on ia32, r1:r0 on ARM).
8970// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8971// In Win64 calling convention, a struct of two pointers is returned in memory,
8972// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008973#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008974struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008975 MaybeObject* x;
8976 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008977};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008978
lrn@chromium.org303ada72010-10-27 09:33:13 +00008979static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008980 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008981 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8982 // In Win64 they are assigned to a hidden first argument.
8983 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008984}
8985#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008986typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008987static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008988 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008989 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008990}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008991#endif
8992
8993
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008994static inline MaybeObject* Unhole(Heap* heap,
8995 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008996 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008997 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8998 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008999 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009000}
9001
9002
danno@chromium.org40cb8782011-05-25 07:58:50 +00009003static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9004 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009005 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009006 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009007 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009008 JSFunction* context_extension_function =
9009 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009010 // If the holder isn't a context extension object, we just return it
9011 // as the receiver. This allows arguments objects to be used as
9012 // receivers, but only if they are put in the context scope chain
9013 // explicitly via a with-statement.
9014 Object* constructor = holder->map()->constructor();
9015 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00009016 // Fall back to using the global object as the implicit receiver if
9017 // the property turns out to be a local variable allocated in a
9018 // context extension object - introduced via eval. Implicit global
9019 // receivers are indicated with the hole value.
9020 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009021}
9022
9023
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009024static ObjectPair LoadContextSlotHelper(Arguments args,
9025 Isolate* isolate,
9026 bool throw_error) {
9027 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009028 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009029
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009030 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009031 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009032 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009033 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009034 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009035
9036 int index;
9037 PropertyAttributes attributes;
9038 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009039 BindingFlags binding_flags;
9040 Handle<Object> holder = context->Lookup(name,
9041 flags,
9042 &index,
9043 &attributes,
9044 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009045
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009046 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009047 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009048 ASSERT(holder->IsContext());
9049 // If the "property" we were looking for is a local variable, the
9050 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009051 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009052 // Use the hole as the receiver to signal that the receiver is implicit
9053 // and that the global receiver should be used (as distinguished from an
9054 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009055 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009056 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009057 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009058 switch (binding_flags) {
9059 case MUTABLE_CHECK_INITIALIZED:
9060 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9061 if (value->IsTheHole()) {
9062 Handle<Object> reference_error =
9063 isolate->factory()->NewReferenceError("not_defined",
9064 HandleVector(&name, 1));
9065 return MakePair(isolate->Throw(*reference_error), NULL);
9066 }
9067 // FALLTHROUGH
9068 case MUTABLE_IS_INITIALIZED:
9069 case IMMUTABLE_IS_INITIALIZED:
9070 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9071 ASSERT(!value->IsTheHole());
9072 return MakePair(value, *receiver);
9073 case IMMUTABLE_CHECK_INITIALIZED:
9074 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9075 case MISSING_BINDING:
9076 UNREACHABLE();
9077 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009078 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009079 }
9080
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009081 // Otherwise, if the slot was found the holder is a context extension
9082 // object, subject of a with, or a global object. We read the named
9083 // property from it.
9084 if (!holder.is_null()) {
9085 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9086 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009087 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009088 Handle<Object> receiver_handle(object->IsGlobalObject()
9089 ? GlobalObject::cast(*object)->global_receiver()
9090 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009091
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009092 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009093 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009094 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009095 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009096 }
9097
9098 if (throw_error) {
9099 // The property doesn't exist - throw exception.
9100 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009101 isolate->factory()->NewReferenceError("not_defined",
9102 HandleVector(&name, 1));
9103 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009104 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009105 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009106 return MakePair(isolate->heap()->undefined_value(),
9107 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009108 }
9109}
9110
9111
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009112RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009113 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009114}
9115
9116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009117RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009118 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119}
9120
9121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009122RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009123 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009124 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009125
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009126 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009127 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009128 CONVERT_ARG_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009129 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9130 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9131 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009132
9133 int index;
9134 PropertyAttributes attributes;
9135 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009136 BindingFlags binding_flags;
9137 Handle<Object> holder = context->Lookup(name,
9138 flags,
9139 &index,
9140 &attributes,
9141 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142
9143 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009144 // The property was found in a context slot.
9145 Handle<Context> context = Handle<Context>::cast(holder);
9146 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9147 context->get(index)->IsTheHole()) {
9148 Handle<Object> error =
9149 isolate->factory()->NewReferenceError("not_defined",
9150 HandleVector(&name, 1));
9151 return isolate->Throw(*error);
9152 }
9153 // Ignore if read_only variable.
9154 if ((attributes & READ_ONLY) == 0) {
9155 // Context is a fixed array and set cannot fail.
9156 context->set(index, *value);
9157 } else if (strict_mode == kStrictMode) {
9158 // Setting read only property in strict mode.
9159 Handle<Object> error =
9160 isolate->factory()->NewTypeError("strict_cannot_assign",
9161 HandleVector(&name, 1));
9162 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009163 }
9164 return *value;
9165 }
9166
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009167 // Slow case: The property is not in a context slot. It is either in a
9168 // context extension object, a property of the subject of a with, or a
9169 // property of the global object.
9170 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009172 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009173 // The property exists on the holder.
9174 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009175 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009176 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009177 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009178
9179 if (strict_mode == kStrictMode) {
9180 // Throw in strict mode (assignment to undefined variable).
9181 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009182 isolate->factory()->NewReferenceError(
9183 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009184 return isolate->Throw(*error);
9185 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009186 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009187 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009188 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009189 }
9190
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009191 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009192 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009193 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009194 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009195 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009196 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009197 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009198 // Setting read only property in strict mode.
9199 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009200 isolate->factory()->NewTypeError(
9201 "strict_cannot_assign", HandleVector(&name, 1));
9202 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009203 }
9204 return *value;
9205}
9206
9207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009208RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009209 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009210 ASSERT(args.length() == 1);
9211
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009212 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009213}
9214
9215
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009216RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009217 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009218 ASSERT(args.length() == 1);
9219
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009220 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009221}
9222
9223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009224RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009225 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009226 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009227}
9228
9229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009230RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009231 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009232 ASSERT(args.length() == 1);
9233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009234 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009235 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009236 isolate->factory()->NewReferenceError("not_defined",
9237 HandleVector(&name, 1));
9238 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009239}
9240
9241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009242RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009243 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244
9245 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009246 if (isolate->stack_guard()->IsStackOverflow()) {
9247 NoHandleAllocation na;
9248 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009249 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009250
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009251 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252}
9253
9254
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009255static int StackSize() {
9256 int n = 0;
9257 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9258 return n;
9259}
9260
9261
9262static void PrintTransition(Object* result) {
9263 // indentation
9264 { const int nmax = 80;
9265 int n = StackSize();
9266 if (n <= nmax)
9267 PrintF("%4d:%*s", n, n, "");
9268 else
9269 PrintF("%4d:%*s", n, nmax, "...");
9270 }
9271
9272 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009273 JavaScriptFrame::PrintTop(stdout, true, false);
9274 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009275 } else {
9276 // function result
9277 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009278 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009279 PrintF("\n");
9280 }
9281}
9282
9283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009284RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009285 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009286 NoHandleAllocation ha;
9287 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009288 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009289}
9290
9291
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009292RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009293 NoHandleAllocation ha;
9294 PrintTransition(args[0]);
9295 return args[0]; // return TOS
9296}
9297
9298
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009299RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009300 NoHandleAllocation ha;
9301 ASSERT(args.length() == 1);
9302
9303#ifdef DEBUG
9304 if (args[0]->IsString()) {
9305 // If we have a string, assume it's a code "marker"
9306 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009307 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009308 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009309 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9310 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009311 } else {
9312 PrintF("DebugPrint: ");
9313 }
9314 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009315 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009316 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009317 HeapObject::cast(args[0])->map()->Print();
9318 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009319#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009320 // ShortPrint is available in release mode. Print is not.
9321 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009322#endif
9323 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009324 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009325
9326 return args[0]; // return TOS
9327}
9328
9329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009330RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009331 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009333 isolate->PrintStack();
9334 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009335}
9336
9337
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009338RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009339 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009340 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009341
9342 // According to ECMA-262, section 15.9.1, page 117, the precision of
9343 // the number in a Date object representing a particular instant in
9344 // time is milliseconds. Therefore, we floor the result of getting
9345 // the OS time.
9346 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009347 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009348}
9349
9350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009351RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009352 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009353 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009354
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009355 CONVERT_ARG_CHECKED(String, str, 0);
9356 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009357
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009358 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009359
9360 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009361 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009362 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009363 RUNTIME_ASSERT(output->HasFastElements());
9364
9365 AssertNoAllocation no_allocation;
9366
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009367 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009368 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9369 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009370 String::FlatContent str_content = str->GetFlatContent();
9371 if (str_content.IsAscii()) {
9372 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009373 output_array,
9374 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009375 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009376 ASSERT(str_content.IsTwoByte());
9377 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009378 output_array,
9379 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009380 }
9381
9382 if (result) {
9383 return *output;
9384 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009385 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009386 }
9387}
9388
9389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009390RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009391 NoHandleAllocation ha;
9392 ASSERT(args.length() == 1);
9393
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009394 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009395 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009396 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009397}
9398
9399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009400RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009401 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009402 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009403
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009404 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009405}
9406
9407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009408RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009409 NoHandleAllocation ha;
9410 ASSERT(args.length() == 1);
9411
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009412 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009413 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009414}
9415
9416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009417RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009418 ASSERT(args.length() == 1);
9419 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009420 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009421 return JSGlobalObject::cast(global)->global_receiver();
9422}
9423
9424
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009425RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009426 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009427 ASSERT_EQ(1, args.length());
9428 CONVERT_ARG_CHECKED(String, source, 0);
9429
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009430 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009431 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009432 Handle<Object> result;
9433 if (source->IsSeqAsciiString()) {
9434 result = JsonParser<true>::Parse(source);
9435 } else {
9436 result = JsonParser<false>::Parse(source);
9437 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009438 if (result.is_null()) {
9439 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009440 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009441 return Failure::Exception();
9442 }
9443 return *result;
9444}
9445
9446
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009447bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9448 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009449 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9450 // Check with callback if set.
9451 AllowCodeGenerationFromStringsCallback callback =
9452 isolate->allow_code_gen_callback();
9453 if (callback == NULL) {
9454 // No callback set and code generation disallowed.
9455 return false;
9456 } else {
9457 // Callback set. Let it decide if code generation is allowed.
9458 VMState state(isolate, EXTERNAL);
9459 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009460 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009461}
9462
9463
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009464RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009465 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009466 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009467 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009468
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009469 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009470 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009471
9472 // Check if global context allows code generation from
9473 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009474 if (context->allow_code_gen_from_strings()->IsFalse() &&
9475 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009476 return isolate->Throw(*isolate->factory()->NewError(
9477 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9478 }
9479
9480 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009481 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009482 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009483 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009484 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009485 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9486 context,
9487 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009488 return *fun;
9489}
9490
9491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009492static ObjectPair CompileGlobalEval(Isolate* isolate,
9493 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009494 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009495 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009496 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009497 Handle<Context> context = Handle<Context>(isolate->context());
9498 Handle<Context> global_context = Handle<Context>(context->global_context());
9499
9500 // Check if global context allows code generation from
9501 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009502 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9503 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009504 isolate->Throw(*isolate->factory()->NewError(
9505 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9506 return MakePair(Failure::Exception(), NULL);
9507 }
9508
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009509 // Deal with a normal eval call with a string argument. Compile it
9510 // and return the compiled function bound in the local context.
9511 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9512 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009513 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009514 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009515 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009516 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009517 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009518 Handle<JSFunction> compiled =
9519 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009520 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009521 return MakePair(*compiled, *receiver);
9522}
9523
9524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009525RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009526 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009527
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009528 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009529 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009530
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009531 // If "eval" didn't refer to the original GlobalEval, it's not a
9532 // direct call to eval.
9533 // (And even if it is, but the first argument isn't a string, just let
9534 // execution default to an indirect call to eval, which will also return
9535 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009536 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009537 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009538 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009539 }
9540
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009541 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009542 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009543 return CompileGlobalEval(isolate,
9544 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009545 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009546 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009547 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009548}
9549
9550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009551RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009552 // This utility adjusts the property attributes for newly created Function
9553 // object ("new Function(...)") by changing the map.
9554 // All it does is changing the prototype property to enumerable
9555 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009556 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009557 ASSERT(args.length() == 1);
9558 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009559
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009560 Handle<Map> map = func->shared()->is_classic_mode()
9561 ? isolate->function_instance_map()
9562 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009563
9564 ASSERT(func->map()->instance_type() == map->instance_type());
9565 ASSERT(func->map()->instance_size() == map->instance_size());
9566 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009567 return *func;
9568}
9569
9570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009571RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009572 // Allocate a block of memory in NewSpace (filled with a filler).
9573 // Use as fallback for allocation in generated code when NewSpace
9574 // is full.
9575 ASSERT(args.length() == 1);
9576 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9577 int size = size_smi->value();
9578 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9579 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009580 Heap* heap = isolate->heap();
9581 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009582 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009583 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009584 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009585 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009586 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009587 }
9588 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009589 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009590}
9591
9592
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009593// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009594// array. Returns true if the element was pushed on the stack and
9595// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009596RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009597 ASSERT(args.length() == 2);
9598 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009599 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009600 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009601 int length = Smi::cast(array->length())->value();
9602 FixedArray* elements = FixedArray::cast(array->elements());
9603 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009604 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009605 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009606 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009607 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009608 { MaybeObject* maybe_obj =
9609 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009610 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9611 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009612 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009613}
9614
9615
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009616/**
9617 * A simple visitor visits every element of Array's.
9618 * The backend storage can be a fixed array for fast elements case,
9619 * or a dictionary for sparse array. Since Dictionary is a subtype
9620 * of FixedArray, the class can be used by both fast and slow cases.
9621 * The second parameter of the constructor, fast_elements, specifies
9622 * whether the storage is a FixedArray or Dictionary.
9623 *
9624 * An index limit is used to deal with the situation that a result array
9625 * length overflows 32-bit non-negative integer.
9626 */
9627class ArrayConcatVisitor {
9628 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009629 ArrayConcatVisitor(Isolate* isolate,
9630 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009631 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009632 isolate_(isolate),
9633 storage_(Handle<FixedArray>::cast(
9634 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009635 index_offset_(0u),
9636 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009637
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009638 ~ArrayConcatVisitor() {
9639 clear_storage();
9640 }
9641
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009642 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009643 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009644 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009645
9646 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009647 if (index < static_cast<uint32_t>(storage_->length())) {
9648 storage_->set(index, *elm);
9649 return;
9650 }
9651 // Our initial estimate of length was foiled, possibly by
9652 // getters on the arrays increasing the length of later arrays
9653 // during iteration.
9654 // This shouldn't happen in anything but pathological cases.
9655 SetDictionaryMode(index);
9656 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009657 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009658 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009659 Handle<SeededNumberDictionary> dict(
9660 SeededNumberDictionary::cast(*storage_));
9661 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009662 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009663 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009664 // Dictionary needed to grow.
9665 clear_storage();
9666 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009667 }
9668}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009669
9670 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009671 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9672 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009673 } else {
9674 index_offset_ += delta;
9675 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009676 }
9677
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009678 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009679 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009680 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009681 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009682 Handle<Map> map;
9683 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009684 map = isolate_->factory()->GetElementsTransitionMap(array,
9685 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009686 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009687 map = isolate_->factory()->GetElementsTransitionMap(array,
9688 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009689 }
9690 array->set_map(*map);
9691 array->set_length(*length);
9692 array->set_elements(*storage_);
9693 return array;
9694 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009695
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009696 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009697 // Convert storage to dictionary mode.
9698 void SetDictionaryMode(uint32_t index) {
9699 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009700 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009701 Handle<SeededNumberDictionary> slow_storage(
9702 isolate_->factory()->NewSeededNumberDictionary(
9703 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009704 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9705 for (uint32_t i = 0; i < current_length; i++) {
9706 HandleScope loop_scope;
9707 Handle<Object> element(current_storage->get(i));
9708 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009709 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009710 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009711 if (!new_storage.is_identical_to(slow_storage)) {
9712 slow_storage = loop_scope.CloseAndEscape(new_storage);
9713 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009714 }
9715 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009716 clear_storage();
9717 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009718 fast_elements_ = false;
9719 }
9720
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009721 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009722 isolate_->global_handles()->Destroy(
9723 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009724 }
9725
9726 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009727 storage_ = Handle<FixedArray>::cast(
9728 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009729 }
9730
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009731 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009732 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009733 // Index after last seen index. Always less than or equal to
9734 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009735 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009736 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009737};
9738
9739
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009740static uint32_t EstimateElementCount(Handle<JSArray> array) {
9741 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9742 int element_count = 0;
9743 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009744 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009745 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009746 // Fast elements can't have lengths that are not representable by
9747 // a 32-bit signed integer.
9748 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9749 int fast_length = static_cast<int>(length);
9750 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9751 for (int i = 0; i < fast_length; i++) {
9752 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009753 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009754 break;
9755 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009756 case FAST_DOUBLE_ELEMENTS:
9757 // TODO(1810): Decide if it's worthwhile to implement this.
9758 UNREACHABLE();
9759 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009760 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009761 Handle<SeededNumberDictionary> dictionary(
9762 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009763 int capacity = dictionary->Capacity();
9764 for (int i = 0; i < capacity; i++) {
9765 Handle<Object> key(dictionary->KeyAt(i));
9766 if (dictionary->IsKey(*key)) {
9767 element_count++;
9768 }
9769 }
9770 break;
9771 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009772 case NON_STRICT_ARGUMENTS_ELEMENTS:
9773 case EXTERNAL_BYTE_ELEMENTS:
9774 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9775 case EXTERNAL_SHORT_ELEMENTS:
9776 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9777 case EXTERNAL_INT_ELEMENTS:
9778 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9779 case EXTERNAL_FLOAT_ELEMENTS:
9780 case EXTERNAL_DOUBLE_ELEMENTS:
9781 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009782 // External arrays are always dense.
9783 return length;
9784 }
9785 // As an estimate, we assume that the prototype doesn't contain any
9786 // inherited elements.
9787 return element_count;
9788}
9789
9790
9791
9792template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009793static void IterateExternalArrayElements(Isolate* isolate,
9794 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009795 bool elements_are_ints,
9796 bool elements_are_guaranteed_smis,
9797 ArrayConcatVisitor* visitor) {
9798 Handle<ExternalArrayClass> array(
9799 ExternalArrayClass::cast(receiver->elements()));
9800 uint32_t len = static_cast<uint32_t>(array->length());
9801
9802 ASSERT(visitor != NULL);
9803 if (elements_are_ints) {
9804 if (elements_are_guaranteed_smis) {
9805 for (uint32_t j = 0; j < len; j++) {
9806 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009807 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009808 visitor->visit(j, e);
9809 }
9810 } else {
9811 for (uint32_t j = 0; j < len; j++) {
9812 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009813 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009814 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9815 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9816 visitor->visit(j, e);
9817 } else {
9818 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009819 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009820 visitor->visit(j, e);
9821 }
9822 }
9823 }
9824 } else {
9825 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009826 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009827 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009828 visitor->visit(j, e);
9829 }
9830 }
9831}
9832
9833
9834// Used for sorting indices in a List<uint32_t>.
9835static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9836 uint32_t a = *ap;
9837 uint32_t b = *bp;
9838 return (a == b) ? 0 : (a < b) ? -1 : 1;
9839}
9840
9841
9842static void CollectElementIndices(Handle<JSObject> object,
9843 uint32_t range,
9844 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009845 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009846 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009847 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009848 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009849 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9850 uint32_t length = static_cast<uint32_t>(elements->length());
9851 if (range < length) length = range;
9852 for (uint32_t i = 0; i < length; i++) {
9853 if (!elements->get(i)->IsTheHole()) {
9854 indices->Add(i);
9855 }
9856 }
9857 break;
9858 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009859 case FAST_DOUBLE_ELEMENTS: {
9860 // TODO(1810): Decide if it's worthwhile to implement this.
9861 UNREACHABLE();
9862 break;
9863 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009864 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009865 Handle<SeededNumberDictionary> dict(
9866 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009867 uint32_t capacity = dict->Capacity();
9868 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009869 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009870 Handle<Object> k(dict->KeyAt(j));
9871 if (dict->IsKey(*k)) {
9872 ASSERT(k->IsNumber());
9873 uint32_t index = static_cast<uint32_t>(k->Number());
9874 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009875 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009876 }
9877 }
9878 }
9879 break;
9880 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009881 default: {
9882 int dense_elements_length;
9883 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009884 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009885 dense_elements_length =
9886 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009887 break;
9888 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009889 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009890 dense_elements_length =
9891 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009892 break;
9893 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009894 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009895 dense_elements_length =
9896 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009897 break;
9898 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009899 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009900 dense_elements_length =
9901 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009902 break;
9903 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009904 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009905 dense_elements_length =
9906 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009907 break;
9908 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009909 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009910 dense_elements_length =
9911 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009912 break;
9913 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009914 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009915 dense_elements_length =
9916 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009917 break;
9918 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009919 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009920 dense_elements_length =
9921 ExternalFloatArray::cast(object->elements())->length();
9922 break;
9923 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009924 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009925 dense_elements_length =
9926 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009927 break;
9928 }
9929 default:
9930 UNREACHABLE();
9931 dense_elements_length = 0;
9932 break;
9933 }
9934 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9935 if (range <= length) {
9936 length = range;
9937 // We will add all indices, so we might as well clear it first
9938 // and avoid duplicates.
9939 indices->Clear();
9940 }
9941 for (uint32_t i = 0; i < length; i++) {
9942 indices->Add(i);
9943 }
9944 if (length == range) return; // All indices accounted for already.
9945 break;
9946 }
9947 }
9948
9949 Handle<Object> prototype(object->GetPrototype());
9950 if (prototype->IsJSObject()) {
9951 // The prototype will usually have no inherited element indices,
9952 // but we have to check.
9953 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9954 }
9955}
9956
9957
9958/**
9959 * A helper function that visits elements of a JSArray in numerical
9960 * order.
9961 *
9962 * The visitor argument called for each existing element in the array
9963 * with the element index and the element's value.
9964 * Afterwards it increments the base-index of the visitor by the array
9965 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009966 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009967 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009968static bool IterateElements(Isolate* isolate,
9969 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009970 ArrayConcatVisitor* visitor) {
9971 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9972 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009973 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009974 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009975 // Run through the elements FixedArray and use HasElement and GetElement
9976 // to check the prototype for missing elements.
9977 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9978 int fast_length = static_cast<int>(length);
9979 ASSERT(fast_length <= elements->length());
9980 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009981 HandleScope loop_scope(isolate);
9982 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009983 if (!element_value->IsTheHole()) {
9984 visitor->visit(j, element_value);
9985 } else if (receiver->HasElement(j)) {
9986 // Call GetElement on receiver, not its prototype, or getters won't
9987 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009988 element_value = Object::GetElement(receiver, j);
9989 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009990 visitor->visit(j, element_value);
9991 }
9992 }
9993 break;
9994 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009995 case FAST_DOUBLE_ELEMENTS: {
9996 // TODO(1810): Decide if it's worthwhile to implement this.
9997 UNREACHABLE();
9998 break;
9999 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010000 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010001 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010002 List<uint32_t> indices(dict->Capacity() / 2);
10003 // Collect all indices in the object and the prototypes less
10004 // than length. This might introduce duplicates in the indices list.
10005 CollectElementIndices(receiver, length, &indices);
10006 indices.Sort(&compareUInt32);
10007 int j = 0;
10008 int n = indices.length();
10009 while (j < n) {
10010 HandleScope loop_scope;
10011 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010012 Handle<Object> element = Object::GetElement(receiver, index);
10013 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010014 visitor->visit(index, element);
10015 // Skip to next different index (i.e., omit duplicates).
10016 do {
10017 j++;
10018 } while (j < n && indices[j] == index);
10019 }
10020 break;
10021 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010022 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010023 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10024 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010025 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010026 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010027 visitor->visit(j, e);
10028 }
10029 break;
10030 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010031 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010032 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010033 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010034 break;
10035 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010036 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010037 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010038 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010039 break;
10040 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010041 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010042 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010043 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010044 break;
10045 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010046 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010047 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010048 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010049 break;
10050 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010051 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010052 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010053 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010054 break;
10055 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010056 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010057 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010058 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010059 break;
10060 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010061 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010062 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010063 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010064 break;
10065 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010066 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010067 IterateExternalArrayElements<ExternalDoubleArray, double>(
10068 isolate, receiver, false, false, visitor);
10069 break;
10070 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010071 default:
10072 UNREACHABLE();
10073 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010074 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010075 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010076 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010077}
10078
10079
10080/**
10081 * Array::concat implementation.
10082 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010083 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010084 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010085 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010086RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010087 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010088 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010089
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010090 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10091 int argument_count = static_cast<int>(arguments->length()->Number());
10092 RUNTIME_ASSERT(arguments->HasFastElements());
10093 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010094
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010095 // Pass 1: estimate the length and number of elements of the result.
10096 // The actual length can be larger if any of the arguments have getters
10097 // that mutate other arguments (but will otherwise be precise).
10098 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010099
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010100 uint32_t estimate_result_length = 0;
10101 uint32_t estimate_nof_elements = 0;
10102 {
10103 for (int i = 0; i < argument_count; i++) {
10104 HandleScope loop_scope;
10105 Handle<Object> obj(elements->get(i));
10106 uint32_t length_estimate;
10107 uint32_t element_estimate;
10108 if (obj->IsJSArray()) {
10109 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010110 // TODO(1810): Find out if it's worthwhile to properly support
10111 // arbitrary ElementsKinds. For now, pessimistically transition to
10112 // FAST_ELEMENTS.
10113 if (array->HasFastDoubleElements()) {
10114 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010115 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010116 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010117 length_estimate =
10118 static_cast<uint32_t>(array->length()->Number());
10119 element_estimate =
10120 EstimateElementCount(array);
10121 } else {
10122 length_estimate = 1;
10123 element_estimate = 1;
10124 }
10125 // Avoid overflows by capping at kMaxElementCount.
10126 if (JSObject::kMaxElementCount - estimate_result_length <
10127 length_estimate) {
10128 estimate_result_length = JSObject::kMaxElementCount;
10129 } else {
10130 estimate_result_length += length_estimate;
10131 }
10132 if (JSObject::kMaxElementCount - estimate_nof_elements <
10133 element_estimate) {
10134 estimate_nof_elements = JSObject::kMaxElementCount;
10135 } else {
10136 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010137 }
10138 }
10139 }
10140
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010141 // If estimated number of elements is more than half of length, a
10142 // fixed array (fast case) is more time and space-efficient than a
10143 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010144 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010145
10146 Handle<FixedArray> storage;
10147 if (fast_case) {
10148 // The backing storage array must have non-existing elements to
10149 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010150 storage = isolate->factory()->NewFixedArrayWithHoles(
10151 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010152 } else {
10153 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10154 uint32_t at_least_space_for = estimate_nof_elements +
10155 (estimate_nof_elements >> 2);
10156 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010157 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010158 }
10159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010160 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010161
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010162 for (int i = 0; i < argument_count; i++) {
10163 Handle<Object> obj(elements->get(i));
10164 if (obj->IsJSArray()) {
10165 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010166 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010167 return Failure::Exception();
10168 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010169 } else {
10170 visitor.visit(0, obj);
10171 visitor.increase_index_offset(1);
10172 }
10173 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010174
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010175 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010176}
10177
10178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010179// This will not allocate (flatten the string), but it may run
10180// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010181RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010182 NoHandleAllocation ha;
10183 ASSERT(args.length() == 1);
10184
10185 CONVERT_CHECKED(String, string, args[0]);
10186 StringInputBuffer buffer(string);
10187 while (buffer.has_more()) {
10188 uint16_t character = buffer.GetNext();
10189 PrintF("%c", character);
10190 }
10191 return string;
10192}
10193
ager@chromium.org5ec48922009-05-05 07:25:34 +000010194// Moves all own elements of an object, that are below a limit, to positions
10195// starting at zero. All undefined values are placed after non-undefined values,
10196// and are followed by non-existing element. Does not change the length
10197// property.
10198// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010199RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010200 ASSERT(args.length() == 2);
10201 CONVERT_CHECKED(JSObject, object, args[0]);
10202 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10203 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010204}
10205
10206
10207// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010208RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010209 ASSERT(args.length() == 2);
10210 CONVERT_CHECKED(JSArray, from, args[0]);
10211 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010212 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010213 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010214 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010215 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10216 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010217 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010218 } else if (new_elements->map() ==
10219 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010220 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010221 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010222 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010223 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010224 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010225 Object* new_map;
10226 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010227 to->set_map(Map::cast(new_map));
10228 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010229 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010230 Object* obj;
10231 { MaybeObject* maybe_obj = from->ResetElements();
10232 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10233 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010234 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010235 return to;
10236}
10237
10238
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010239// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010240RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010241 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010242 CONVERT_CHECKED(JSObject, object, args[0]);
10243 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010244 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010245 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10246 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010247 } else if (object->IsJSArray()) {
10248 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010249 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010250 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010251 }
10252}
10253
10254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010255RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010256 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010257
10258 ASSERT_EQ(3, args.length());
10259
ager@chromium.orgac091b72010-05-05 07:34:42 +000010260 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010261 Handle<Object> key1 = args.at<Object>(1);
10262 Handle<Object> key2 = args.at<Object>(2);
10263
10264 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010265 if (!key1->ToArrayIndex(&index1)
10266 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010267 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010268 }
10269
ager@chromium.orgac091b72010-05-05 07:34:42 +000010270 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010271 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010272 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010273 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010274 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010275
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010276 RETURN_IF_EMPTY_HANDLE(
10277 isolate, JSObject::SetElement(jsobject, index1, tmp2, kStrictMode));
10278 RETURN_IF_EMPTY_HANDLE(
10279 isolate, JSObject::SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010280
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010281 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010282}
10283
10284
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010285// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010286// might have elements. Can either return keys (positive integers) or
10287// intervals (pair of a negative integer (-start-1) followed by a
10288// positive (length)) or undefined values.
10289// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010290RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010291 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010292 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010293 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010295 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296 // Create an array and get all the keys into it, then remove all the
10297 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010298 bool threw = false;
10299 Handle<FixedArray> keys =
10300 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10301 if (threw) return Failure::Exception();
10302
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010303 int keys_length = keys->length();
10304 for (int i = 0; i < keys_length; i++) {
10305 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010306 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010307 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010308 // Zap invalid keys.
10309 keys->set_undefined(i);
10310 }
10311 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010312 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010313 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010314 ASSERT(array->HasFastElements() ||
10315 array->HasFastSmiOnlyElements() ||
10316 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010317 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010318 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010319 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010320 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010321 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010322 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010323 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010325 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010326 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010327 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010328 }
10329}
10330
10331
10332// DefineAccessor takes an optional final argument which is the
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010333// property attributes (e.g. DONT_ENUM, DONT_DELETE). IMPORTANT: due
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010334// to the way accessors are implemented, it is set for both the getter
10335// and setter on the first call to DefineAccessor and ignored on
10336// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010337RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010338 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10339 // Compute attributes.
10340 PropertyAttributes attributes = NONE;
10341 if (args.length() == 5) {
10342 CONVERT_CHECKED(Smi, attrs, args[4]);
10343 int value = attrs->value();
10344 // Only attribute bits should be set.
10345 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10346 attributes = static_cast<PropertyAttributes>(value);
10347 }
10348
10349 CONVERT_CHECKED(JSObject, obj, args[0]);
10350 CONVERT_CHECKED(String, name, args[1]);
10351 CONVERT_CHECKED(Smi, flag, args[2]);
10352 CONVERT_CHECKED(JSFunction, fun, args[3]);
10353 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10354}
10355
10356
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010357RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010358 ASSERT(args.length() == 3);
10359 CONVERT_CHECKED(JSObject, obj, args[0]);
10360 CONVERT_CHECKED(String, name, args[1]);
10361 CONVERT_CHECKED(Smi, flag, args[2]);
10362 return obj->LookupAccessor(name, flag->value() == 0);
10363}
10364
10365
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010366#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010367RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010368 ASSERT(args.length() == 0);
10369 return Execution::DebugBreakHelper();
10370}
10371
10372
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010373// Helper functions for wrapping and unwrapping stack frame ids.
10374static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010375 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010376 return Smi::FromInt(id >> 2);
10377}
10378
10379
10380static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10381 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10382}
10383
10384
10385// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010386// args[0]: debug event listener function to set or null or undefined for
10387// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010388// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010389RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010390 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010391 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10392 args[0]->IsUndefined() ||
10393 args[0]->IsNull());
10394 Handle<Object> callback = args.at<Object>(0);
10395 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010396 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010398 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010399}
10400
10401
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010402RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010403 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010404 isolate->stack_guard()->DebugBreak();
10405 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010406}
10407
10408
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010409static MaybeObject* DebugLookupResultValue(Heap* heap,
10410 Object* receiver,
10411 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010412 LookupResult* result,
10413 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010414 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010415 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010416 case NORMAL:
10417 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010418 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010419 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010420 }
10421 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010422 case FIELD:
10423 value =
10424 JSObject::cast(
10425 result->holder())->FastPropertyAt(result->GetFieldIndex());
10426 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010427 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010428 }
10429 return value;
10430 case CONSTANT_FUNCTION:
10431 return result->GetConstantFunction();
10432 case CALLBACKS: {
10433 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010434 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010435 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10436 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010437 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010438 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010439 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010440 maybe_value = heap->isolate()->pending_exception();
10441 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010442 if (caught_exception != NULL) {
10443 *caught_exception = true;
10444 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010445 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010446 }
10447 return value;
10448 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010449 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010450 }
10451 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010452 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010453 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010454 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010455 case CONSTANT_TRANSITION:
10456 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010457 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010458 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010459 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010460 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010461 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010462 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010463 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010464}
10465
10466
ager@chromium.org32912102009-01-16 10:38:43 +000010467// Get debugger related details for an object property.
10468// args[0]: object holding property
10469// args[1]: name of the property
10470//
10471// The array returned contains the following information:
10472// 0: Property value
10473// 1: Property details
10474// 2: Property value is exception
10475// 3: Getter function if defined
10476// 4: Setter function if defined
10477// Items 2-4 are only filled if the property has either a getter or a setter
10478// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010479RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010480 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010481
10482 ASSERT(args.length() == 2);
10483
10484 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10485 CONVERT_ARG_CHECKED(String, name, 1);
10486
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010487 // Make sure to set the current context to the context before the debugger was
10488 // entered (if the debugger is entered). The reason for switching context here
10489 // is that for some property lookups (accessors and interceptors) callbacks
10490 // into the embedding application can occour, and the embedding application
10491 // could have the assumption that its own global context is the current
10492 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010493 SaveContext save(isolate);
10494 if (isolate->debug()->InDebugger()) {
10495 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010496 }
10497
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010498 // Skip the global proxy as it has no properties and always delegates to the
10499 // real global object.
10500 if (obj->IsJSGlobalProxy()) {
10501 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10502 }
10503
10504
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010505 // Check if the name is trivially convertible to an index and get the element
10506 // if so.
10507 uint32_t index;
10508 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010509 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010510 Object* element_or_char;
10511 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010512 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010513 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10514 return maybe_element_or_char;
10515 }
10516 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010517 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010519 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010520 }
10521
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010522 // Find the number of objects making up this.
10523 int length = LocalPrototypeChainLength(*obj);
10524
10525 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010526 Handle<JSObject> jsproto = obj;
10527 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010528 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010529 jsproto->LocalLookup(*name, &result);
10530 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010531 // LookupResult is not GC safe as it holds raw object pointers.
10532 // GC can happen later in this code so put the required fields into
10533 // local variables using handles when required for later use.
10534 PropertyType result_type = result.type();
10535 Handle<Object> result_callback_obj;
10536 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010537 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10538 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010539 }
10540 Smi* property_details = result.GetPropertyDetails().AsSmi();
10541 // DebugLookupResultValue can cause GC so details from LookupResult needs
10542 // to be copied to handles before this.
10543 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010544 Object* raw_value;
10545 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010546 DebugLookupResultValue(isolate->heap(), *obj, *name,
10547 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010548 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10549 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010550 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010551
10552 // If the callback object is a fixed array then it contains JavaScript
10553 // getter and/or setter.
10554 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010555 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010556 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010557 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010558 details->set(0, *value);
10559 details->set(1, property_details);
10560 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010561 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010562 details->set(3, AccessorPair::cast(*result_callback_obj)->getter());
10563 details->set(4, AccessorPair::cast(*result_callback_obj)->setter());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010564 }
10565
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010566 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010567 }
10568 if (i < length - 1) {
10569 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10570 }
10571 }
10572
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010573 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574}
10575
10576
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010577RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010578 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010579
10580 ASSERT(args.length() == 2);
10581
10582 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10583 CONVERT_ARG_CHECKED(String, name, 1);
10584
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010585 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010586 obj->Lookup(*name, &result);
10587 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010588 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010589 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010590 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010591}
10592
10593
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010594// Return the property type calculated from the property details.
10595// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010596RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010597 ASSERT(args.length() == 1);
10598 CONVERT_CHECKED(Smi, details, args[0]);
10599 PropertyType type = PropertyDetails(details).type();
10600 return Smi::FromInt(static_cast<int>(type));
10601}
10602
10603
10604// Return the property attribute calculated from the property details.
10605// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010606RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607 ASSERT(args.length() == 1);
10608 CONVERT_CHECKED(Smi, details, args[0]);
10609 PropertyAttributes attributes = PropertyDetails(details).attributes();
10610 return Smi::FromInt(static_cast<int>(attributes));
10611}
10612
10613
10614// Return the property insertion index calculated from the property details.
10615// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010616RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010617 ASSERT(args.length() == 1);
10618 CONVERT_CHECKED(Smi, details, args[0]);
10619 int index = PropertyDetails(details).index();
10620 return Smi::FromInt(index);
10621}
10622
10623
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010624// Return property value from named interceptor.
10625// args[0]: object
10626// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010627RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010628 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010629 ASSERT(args.length() == 2);
10630 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10631 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10632 CONVERT_ARG_CHECKED(String, name, 1);
10633
10634 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010635 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010636}
10637
10638
10639// Return element value from indexed interceptor.
10640// args[0]: object
10641// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010642RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010643 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644 ASSERT(args.length() == 2);
10645 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10646 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10647 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10648
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010649 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010650}
10651
10652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010653RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010654 ASSERT(args.length() >= 1);
10655 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010656 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010657 if (isolate->debug()->break_id() == 0 ||
10658 break_id != isolate->debug()->break_id()) {
10659 return isolate->Throw(
10660 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010661 }
10662
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010663 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664}
10665
10666
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010667RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010668 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010669 ASSERT(args.length() == 1);
10670
10671 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010672 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010673 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10674 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010675 if (!maybe_result->ToObject(&result)) return maybe_result;
10676 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010677
10678 // Count all frames which are relevant to debugging stack trace.
10679 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010680 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010681 if (id == StackFrame::NO_ID) {
10682 // If there is no JavaScript stack frame count is 0.
10683 return Smi::FromInt(0);
10684 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010685
10686 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10687 n += it.frame()->GetInlineCount();
10688 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010689 return Smi::FromInt(n);
10690}
10691
10692
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010693class FrameInspector {
10694 public:
10695 FrameInspector(JavaScriptFrame* frame,
10696 int inlined_frame_index,
10697 Isolate* isolate)
10698 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10699 // Calculate the deoptimized frame.
10700 if (frame->is_optimized()) {
10701 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10702 frame, inlined_frame_index, isolate);
10703 }
10704 has_adapted_arguments_ = frame_->has_adapted_arguments();
10705 is_optimized_ = frame_->is_optimized();
10706 }
10707
10708 ~FrameInspector() {
10709 // Get rid of the calculated deoptimized frame if any.
10710 if (deoptimized_frame_ != NULL) {
10711 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10712 isolate_);
10713 }
10714 }
10715
10716 int GetParametersCount() {
10717 return is_optimized_
10718 ? deoptimized_frame_->parameters_count()
10719 : frame_->ComputeParametersCount();
10720 }
10721 int expression_count() { return deoptimized_frame_->expression_count(); }
10722 Object* GetFunction() {
10723 return is_optimized_
10724 ? deoptimized_frame_->GetFunction()
10725 : frame_->function();
10726 }
10727 Object* GetParameter(int index) {
10728 return is_optimized_
10729 ? deoptimized_frame_->GetParameter(index)
10730 : frame_->GetParameter(index);
10731 }
10732 Object* GetExpression(int index) {
10733 return is_optimized_
10734 ? deoptimized_frame_->GetExpression(index)
10735 : frame_->GetExpression(index);
10736 }
10737
10738 // To inspect all the provided arguments the frame might need to be
10739 // replaced with the arguments frame.
10740 void SetArgumentsFrame(JavaScriptFrame* frame) {
10741 ASSERT(has_adapted_arguments_);
10742 frame_ = frame;
10743 is_optimized_ = frame_->is_optimized();
10744 ASSERT(!is_optimized_);
10745 }
10746
10747 private:
10748 JavaScriptFrame* frame_;
10749 DeoptimizedFrameInfo* deoptimized_frame_;
10750 Isolate* isolate_;
10751 bool is_optimized_;
10752 bool has_adapted_arguments_;
10753
10754 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10755};
10756
10757
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010758static const int kFrameDetailsFrameIdIndex = 0;
10759static const int kFrameDetailsReceiverIndex = 1;
10760static const int kFrameDetailsFunctionIndex = 2;
10761static const int kFrameDetailsArgumentCountIndex = 3;
10762static const int kFrameDetailsLocalCountIndex = 4;
10763static const int kFrameDetailsSourcePositionIndex = 5;
10764static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010765static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010766static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010767static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010768
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010769
10770static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10771 JavaScriptFrame* frame) {
10772 SaveContext* save = isolate->save_context();
10773 while (save != NULL && !save->IsBelowFrame(frame)) {
10774 save = save->prev();
10775 }
10776 ASSERT(save != NULL);
10777 return save;
10778}
10779
10780
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010781// Return an array with frame details
10782// args[0]: number: break id
10783// args[1]: number: frame index
10784//
10785// The array returned contains the following information:
10786// 0: Frame id
10787// 1: Receiver
10788// 2: Function
10789// 3: Argument count
10790// 4: Local count
10791// 5: Source position
10792// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010793// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010794// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010795// Arguments name, value
10796// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010797// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010798RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010799 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010800 ASSERT(args.length() == 2);
10801
10802 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010803 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010804 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10805 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010806 if (!maybe_check->ToObject(&check)) return maybe_check;
10807 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010808 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010809 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010810
10811 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010812 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010813 if (id == StackFrame::NO_ID) {
10814 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010815 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010816 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010817
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010818 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010819
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010820 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010821 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010822 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010823 if (index < count + it.frame()->GetInlineCount()) break;
10824 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010825 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010826 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010827
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010828 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010829 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010830 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010831 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010832 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010833
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010834 // Traverse the saved contexts chain to find the active context for the
10835 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010836 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010837
10838 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010839 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010840
10841 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010842 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010843 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010844
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010845 // Check for constructor frame. Inlined frames cannot be construct calls.
10846 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010847 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010848 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010849
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010850 // Get scope info and read from it for local variable information.
10851 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010852 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010853 Handle<ScopeInfo> scope_info(shared->scope_info());
10854 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010855
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010856 // Get the locals names and values into a temporary array.
10857 //
10858 // TODO(1240907): Hide compiler-introduced stack variables
10859 // (e.g. .result)? For users of the debugger, they will probably be
10860 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010861 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010862 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010863
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010864 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010865 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010866 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010867 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010868 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010869 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010870 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010871 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010872 // Get the context containing declarations.
10873 Handle<Context> context(
10874 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010875 for (; i < scope_info->LocalCount(); ++i) {
10876 Handle<String> name(scope_info->LocalName(i));
10877 VariableMode mode;
10878 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010879 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010880 locals->set(i * 2 + 1, context->get(
10881 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010882 }
10883 }
10884
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010885 // Check whether this frame is positioned at return. If not top
10886 // frame or if the frame is optimized it cannot be at a return.
10887 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010888 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010889 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010890 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010891
10892 // If positioned just before return find the value to be returned and add it
10893 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010894 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010895 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010896 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010897 Address internal_frame_sp = NULL;
10898 while (!it2.done()) {
10899 if (it2.frame()->is_internal()) {
10900 internal_frame_sp = it2.frame()->sp();
10901 } else {
10902 if (it2.frame()->is_java_script()) {
10903 if (it2.frame()->id() == it.frame()->id()) {
10904 // The internal frame just before the JavaScript frame contains the
10905 // value to return on top. A debug break at return will create an
10906 // internal frame to store the return value (eax/rax/r0) before
10907 // entering the debug break exit frame.
10908 if (internal_frame_sp != NULL) {
10909 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010910 Handle<Object>(Memory::Object_at(internal_frame_sp),
10911 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010912 break;
10913 }
10914 }
10915 }
10916
10917 // Indicate that the previous frame was not an internal frame.
10918 internal_frame_sp = NULL;
10919 }
10920 it2.Advance();
10921 }
10922 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010923
10924 // Now advance to the arguments adapter frame (if any). It contains all
10925 // the provided parameters whereas the function frame always have the number
10926 // of arguments matching the functions parameters. The rest of the
10927 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010928 if (it.frame()->has_adapted_arguments()) {
10929 it.AdvanceToArgumentsFrame();
10930 frame_inspector.SetArgumentsFrame(it.frame());
10931 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010932
10933 // Find the number of arguments to fill. At least fill the number of
10934 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010935 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010936 if (argument_count < frame_inspector.GetParametersCount()) {
10937 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010938 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010939#ifdef DEBUG
10940 if (it.frame()->is_optimized()) {
10941 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10942 }
10943#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010944
10945 // Calculate the size of the result.
10946 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010947 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010948 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010949 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950
10951 // Add the frame id.
10952 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10953
10954 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010955 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010956
10957 // Add the arguments count.
10958 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10959
10960 // Add the locals count
10961 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010962 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010963
10964 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010965 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010966 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10967 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010968 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010969 }
10970
10971 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010972 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010973
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010974 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010975 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010976
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010977 // Add flags to indicate information on whether this frame is
10978 // bit 0: invoked in the debugger context.
10979 // bit 1: optimized frame.
10980 // bit 2: inlined in optimized frame
10981 int flags = 0;
10982 if (*save->context() == *isolate->debug()->debug_context()) {
10983 flags |= 1 << 0;
10984 }
10985 if (it.frame()->is_optimized()) {
10986 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010987 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010988 }
10989 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010990
10991 // Fill the dynamic part.
10992 int details_index = kFrameDetailsFirstDynamicIndex;
10993
10994 // Add arguments name and value.
10995 for (int i = 0; i < argument_count; i++) {
10996 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010997 if (i < scope_info->ParameterCount()) {
10998 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010999 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011000 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011001 }
11002
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011003 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011004 if (i < it.frame()->ComputeParametersCount()) {
11005 // Get the value from the stack.
11006 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011007 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011008 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011009 }
11010 }
11011
11012 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011013 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011014 details->set(details_index++, locals->get(i));
11015 }
11016
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011017 // Add the value being returned.
11018 if (at_return) {
11019 details->set(details_index++, *return_value);
11020 }
11021
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011022 // Add the receiver (same as in function frame).
11023 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11024 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011025 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011026 if (!receiver->IsJSObject() &&
11027 shared->is_classic_mode() &&
11028 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011029 // If the receiver is not a JSObject and the function is not a
11030 // builtin or strict-mode we have hit an optimization where a
11031 // value object is not converted into a wrapped JS objects. To
11032 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011033 // by creating correct wrapper object based on the calling frame's
11034 // global context.
11035 it.Advance();
11036 Handle<Context> calling_frames_global_context(
11037 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011038 receiver =
11039 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011040 }
11041 details->set(kFrameDetailsReceiverIndex, *receiver);
11042
11043 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011044 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011045}
11046
11047
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011048// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011049static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011050 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011051 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011052 Handle<Context> context,
11053 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011054 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011055 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11056 VariableMode mode;
11057 InitializationFlag init_flag;
11058 int context_index = scope_info->ContextSlotIndex(
11059 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011060
whesse@chromium.org7b260152011-06-20 15:33:18 +000011061 RETURN_IF_EMPTY_HANDLE_VALUE(
11062 isolate,
11063 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011064 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011065 Handle<Object>(context->get(context_index), isolate),
11066 NONE,
11067 kNonStrictMode),
11068 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011069 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011070
11071 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011072}
11073
11074
11075// Create a plain JSObject which materializes the local scope for the specified
11076// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011077static Handle<JSObject> MaterializeLocalScope(
11078 Isolate* isolate,
11079 JavaScriptFrame* frame,
11080 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011081 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011082 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011083 Handle<ScopeInfo> scope_info(shared->scope_info());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011084 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011085
11086 // Allocate and initialize a JSObject with all the arguments, stack locals
11087 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011088 Handle<JSObject> local_scope =
11089 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011090
11091 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011092 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011093 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011094 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011095 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011096 Handle<String>(scope_info->ParameterName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011097 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011098 NONE,
11099 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011100 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011101 }
11102
11103 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011104 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011105 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011106 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011107 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011108 Handle<String>(scope_info->StackLocalName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011109 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011110 NONE,
11111 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011112 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011113 }
11114
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011115 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011116 // Third fill all context locals.
11117 Handle<Context> frame_context(Context::cast(frame->context()));
11118 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011119 if (!CopyContextLocalsToScopeObject(
11120 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011121 return Handle<JSObject>();
11122 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011123
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011124 // Finally copy any properties from the function context extension.
11125 // These will be variables introduced by eval.
11126 if (function_context->closure() == *function) {
11127 if (function_context->has_extension() &&
11128 !function_context->IsGlobalContext()) {
11129 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011130 bool threw = false;
11131 Handle<FixedArray> keys =
11132 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11133 if (threw) return Handle<JSObject>();
11134
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011135 for (int i = 0; i < keys->length(); i++) {
11136 // Names of variables introduced by eval are strings.
11137 ASSERT(keys->get(i)->IsString());
11138 Handle<String> key(String::cast(keys->get(i)));
11139 RETURN_IF_EMPTY_HANDLE_VALUE(
11140 isolate,
11141 SetProperty(local_scope,
11142 key,
11143 GetProperty(ext, key),
11144 NONE,
11145 kNonStrictMode),
11146 Handle<JSObject>());
11147 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011148 }
11149 }
11150 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011151
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011152 return local_scope;
11153}
11154
11155
11156// Create a plain JSObject which materializes the closure content for the
11157// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011158static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11159 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011160 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011161
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011162 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011163 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011164
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011165 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011166 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011167 Handle<JSObject> closure_scope =
11168 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011169
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011170 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011171 if (!CopyContextLocalsToScopeObject(
11172 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011173 return Handle<JSObject>();
11174 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011175
11176 // Finally copy any properties from the function context extension. This will
11177 // be variables introduced by eval.
11178 if (context->has_extension()) {
11179 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011180 bool threw = false;
11181 Handle<FixedArray> keys =
11182 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11183 if (threw) return Handle<JSObject>();
11184
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011185 for (int i = 0; i < keys->length(); i++) {
11186 // Names of variables introduced by eval are strings.
11187 ASSERT(keys->get(i)->IsString());
11188 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011189 RETURN_IF_EMPTY_HANDLE_VALUE(
11190 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011191 SetProperty(closure_scope,
11192 key,
11193 GetProperty(ext, key),
11194 NONE,
11195 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011196 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011197 }
11198 }
11199
11200 return closure_scope;
11201}
11202
11203
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011204// Create a plain JSObject which materializes the scope for the specified
11205// catch context.
11206static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11207 Handle<Context> context) {
11208 ASSERT(context->IsCatchContext());
11209 Handle<String> name(String::cast(context->extension()));
11210 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11211 Handle<JSObject> catch_scope =
11212 isolate->factory()->NewJSObject(isolate->object_function());
11213 RETURN_IF_EMPTY_HANDLE_VALUE(
11214 isolate,
11215 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11216 Handle<JSObject>());
11217 return catch_scope;
11218}
11219
11220
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011221// Create a plain JSObject which materializes the block scope for the specified
11222// block context.
11223static Handle<JSObject> MaterializeBlockScope(
11224 Isolate* isolate,
11225 Handle<Context> context) {
11226 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011227 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011228
11229 // Allocate and initialize a JSObject with all the arguments, stack locals
11230 // heap locals and extension properties of the debugged function.
11231 Handle<JSObject> block_scope =
11232 isolate->factory()->NewJSObject(isolate->object_function());
11233
11234 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011235 if (!CopyContextLocalsToScopeObject(
11236 isolate, scope_info, context, block_scope)) {
11237 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011238 }
11239
11240 return block_scope;
11241}
11242
11243
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011244// Iterate over the actual scopes visible from a stack frame. The iteration
11245// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011246// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011247// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011248class ScopeIterator {
11249 public:
11250 enum ScopeType {
11251 ScopeTypeGlobal = 0,
11252 ScopeTypeLocal,
11253 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011254 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011255 ScopeTypeCatch,
11256 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011257 };
11258
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011259 ScopeIterator(Isolate* isolate,
11260 JavaScriptFrame* frame,
11261 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011262 : isolate_(isolate),
11263 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011264 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011265 function_(JSFunction::cast(frame->function())),
11266 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011267 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011268
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011269 // Catch the case when the debugger stops in an internal function.
11270 Handle<SharedFunctionInfo> shared_info(function_->shared());
11271 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11272 if (shared_info->script() == isolate->heap()->undefined_value()) {
11273 while (context_->closure() == *function_) {
11274 context_ = Handle<Context>(context_->previous(), isolate_);
11275 }
11276 return;
11277 }
11278
11279 // Get the debug info (create it if it does not exist).
11280 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11281 // Return if ensuring debug info failed.
11282 return;
11283 }
11284 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11285
11286 // Find the break point where execution has stopped.
11287 BreakLocationIterator break_location_iterator(debug_info,
11288 ALL_BREAK_LOCATIONS);
11289 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11290 if (break_location_iterator.IsExit()) {
11291 // We are within the return sequence. At the momemt it is not possible to
11292 // get a source position which is consistent with the current scope chain.
11293 // Thus all nested with, catch and block contexts are skipped and we only
11294 // provide the function scope.
11295 if (scope_info->HasContext()) {
11296 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11297 } else {
11298 while (context_->closure() == *function_) {
11299 context_ = Handle<Context>(context_->previous(), isolate_);
11300 }
11301 }
11302 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11303 } else {
11304 // Reparse the code and analyze the scopes.
11305 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11306 Handle<Script> script(Script::cast(shared_info->script()));
11307 Scope* scope = NULL;
11308
11309 // Check whether we are in global, eval or function code.
11310 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11311 if (scope_info->Type() != FUNCTION_SCOPE) {
11312 // Global or eval code.
11313 CompilationInfo info(script);
11314 if (scope_info->Type() == GLOBAL_SCOPE) {
11315 info.MarkAsGlobal();
11316 } else {
11317 ASSERT(scope_info->Type() == EVAL_SCOPE);
11318 info.MarkAsEval();
11319 info.SetCallingContext(Handle<Context>(function_->context()));
11320 }
11321 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11322 scope = info.function()->scope();
11323 }
11324 } else {
11325 // Function code
11326 CompilationInfo info(shared_info);
11327 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11328 scope = info.function()->scope();
11329 }
11330 }
11331
11332 // Retrieve the scope chain for the current position.
11333 if (scope != NULL) {
11334 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11335 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11336 } else {
11337 // A failed reparse indicates that the preparser has diverged from the
11338 // parser or that the preparse data given to the initial parse has been
11339 // faulty. We fail in debug mode but in release mode we only provide the
11340 // information we get from the context chain but nothing about
11341 // completely stack allocated scopes or stack allocated locals.
11342 UNREACHABLE();
11343 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011344 }
11345 }
11346
11347 // More scopes?
11348 bool Done() { return context_.is_null(); }
11349
11350 // Move to the next scope.
11351 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011352 ScopeType scope_type = Type();
11353 if (scope_type == ScopeTypeGlobal) {
11354 // The global scope is always the last in the chain.
11355 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011356 context_ = Handle<Context>();
11357 return;
11358 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011359 if (nested_scope_chain_.is_empty()) {
11360 context_ = Handle<Context>(context_->previous(), isolate_);
11361 } else {
11362 if (nested_scope_chain_.last()->HasContext()) {
11363 ASSERT(context_->previous() != NULL);
11364 context_ = Handle<Context>(context_->previous(), isolate_);
11365 }
11366 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011367 }
11368 }
11369
11370 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011371 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011372 if (!nested_scope_chain_.is_empty()) {
11373 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11374 switch (scope_info->Type()) {
11375 case FUNCTION_SCOPE:
11376 ASSERT(context_->IsFunctionContext() ||
11377 !scope_info->HasContext());
11378 return ScopeTypeLocal;
11379 case GLOBAL_SCOPE:
11380 ASSERT(context_->IsGlobalContext());
11381 return ScopeTypeGlobal;
11382 case WITH_SCOPE:
11383 ASSERT(context_->IsWithContext());
11384 return ScopeTypeWith;
11385 case CATCH_SCOPE:
11386 ASSERT(context_->IsCatchContext());
11387 return ScopeTypeCatch;
11388 case BLOCK_SCOPE:
11389 ASSERT(!scope_info->HasContext() ||
11390 context_->IsBlockContext());
11391 return ScopeTypeBlock;
11392 case EVAL_SCOPE:
11393 UNREACHABLE();
11394 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011395 }
11396 if (context_->IsGlobalContext()) {
11397 ASSERT(context_->global()->IsGlobalObject());
11398 return ScopeTypeGlobal;
11399 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011400 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011401 return ScopeTypeClosure;
11402 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011403 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011404 return ScopeTypeCatch;
11405 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011406 if (context_->IsBlockContext()) {
11407 return ScopeTypeBlock;
11408 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011409 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011410 return ScopeTypeWith;
11411 }
11412
11413 // Return the JavaScript object with the content of the current scope.
11414 Handle<JSObject> ScopeObject() {
11415 switch (Type()) {
11416 case ScopeIterator::ScopeTypeGlobal:
11417 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011418 case ScopeIterator::ScopeTypeLocal:
11419 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011420 ASSERT(nested_scope_chain_.length() == 1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011421 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011422 case ScopeIterator::ScopeTypeWith:
11423 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011424 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11425 case ScopeIterator::ScopeTypeCatch:
11426 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011427 case ScopeIterator::ScopeTypeClosure:
11428 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011429 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011430 case ScopeIterator::ScopeTypeBlock:
11431 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011432 }
11433 UNREACHABLE();
11434 return Handle<JSObject>();
11435 }
11436
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011437 Handle<ScopeInfo> CurrentScopeInfo() {
11438 if (!nested_scope_chain_.is_empty()) {
11439 return nested_scope_chain_.last();
11440 } else if (context_->IsBlockContext()) {
11441 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11442 } else if (context_->IsFunctionContext()) {
11443 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11444 }
11445 return Handle<ScopeInfo>::null();
11446 }
11447
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011448 // Return the context for this scope. For the local context there might not
11449 // be an actual context.
11450 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011451 if (Type() == ScopeTypeGlobal ||
11452 nested_scope_chain_.is_empty()) {
11453 return context_;
11454 } else if (nested_scope_chain_.last()->HasContext()) {
11455 return context_;
11456 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011457 return Handle<Context>();
11458 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011459 }
11460
11461#ifdef DEBUG
11462 // Debug print of the content of the current scope.
11463 void DebugPrint() {
11464 switch (Type()) {
11465 case ScopeIterator::ScopeTypeGlobal:
11466 PrintF("Global:\n");
11467 CurrentContext()->Print();
11468 break;
11469
11470 case ScopeIterator::ScopeTypeLocal: {
11471 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011472 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011473 if (!CurrentContext().is_null()) {
11474 CurrentContext()->Print();
11475 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011476 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011477 if (extension->IsJSContextExtensionObject()) {
11478 extension->Print();
11479 }
11480 }
11481 }
11482 break;
11483 }
11484
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011485 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011486 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011487 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011488 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011489
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011490 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011491 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011492 CurrentContext()->extension()->Print();
11493 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011494 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011495
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011496 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011497 PrintF("Closure:\n");
11498 CurrentContext()->Print();
11499 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011500 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011501 if (extension->IsJSContextExtensionObject()) {
11502 extension->Print();
11503 }
11504 }
11505 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011506
11507 default:
11508 UNREACHABLE();
11509 }
11510 PrintF("\n");
11511 }
11512#endif
11513
11514 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011515 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011516 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011517 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011518 Handle<JSFunction> function_;
11519 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011520 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011521
11522 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11523};
11524
11525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011526RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011527 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011528 ASSERT(args.length() == 2);
11529
11530 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011531 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011532 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11533 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011534 if (!maybe_check->ToObject(&check)) return maybe_check;
11535 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011536 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11537
11538 // Get the frame where the debugging is performed.
11539 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011540 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011541 JavaScriptFrame* frame = it.frame();
11542
11543 // Count the visible scopes.
11544 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011545 for (ScopeIterator it(isolate, frame, 0);
11546 !it.Done();
11547 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011548 n++;
11549 }
11550
11551 return Smi::FromInt(n);
11552}
11553
11554
11555static const int kScopeDetailsTypeIndex = 0;
11556static const int kScopeDetailsObjectIndex = 1;
11557static const int kScopeDetailsSize = 2;
11558
11559// Return an array with scope details
11560// args[0]: number: break id
11561// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011562// args[2]: number: inlined frame index
11563// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011564//
11565// The array returned contains the following information:
11566// 0: Scope type
11567// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011568RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011569 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011570 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011571
11572 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011573 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011574 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11575 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011576 if (!maybe_check->ToObject(&check)) return maybe_check;
11577 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011578 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011579 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11580 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011581
11582 // Get the frame where the debugging is performed.
11583 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011584 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011585 JavaScriptFrame* frame = frame_it.frame();
11586
11587 // Find the requested scope.
11588 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011589 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011590 for (; !it.Done() && n < index; it.Next()) {
11591 n++;
11592 }
11593 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011594 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011595 }
11596
11597 // Calculate the size of the result.
11598 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011599 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011600
11601 // Fill in scope details.
11602 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011603 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011604 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011605 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011606
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011607 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011608}
11609
11610
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011611RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011612 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011613 ASSERT(args.length() == 0);
11614
11615#ifdef DEBUG
11616 // Print the scopes for the top frame.
11617 StackFrameLocator locator;
11618 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011619 for (ScopeIterator it(isolate, frame, 0);
11620 !it.Done();
11621 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011622 it.DebugPrint();
11623 }
11624#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011626}
11627
11628
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011629RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011630 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011631 ASSERT(args.length() == 1);
11632
11633 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011634 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011635 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11636 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011637 if (!maybe_result->ToObject(&result)) return maybe_result;
11638 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011639
11640 // Count all archived V8 threads.
11641 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011642 for (ThreadState* thread =
11643 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011644 thread != NULL;
11645 thread = thread->Next()) {
11646 n++;
11647 }
11648
11649 // Total number of threads is current thread and archived threads.
11650 return Smi::FromInt(n + 1);
11651}
11652
11653
11654static const int kThreadDetailsCurrentThreadIndex = 0;
11655static const int kThreadDetailsThreadIdIndex = 1;
11656static const int kThreadDetailsSize = 2;
11657
11658// Return an array with thread details
11659// args[0]: number: break id
11660// args[1]: number: thread index
11661//
11662// The array returned contains the following information:
11663// 0: Is current thread?
11664// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011665RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011666 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011667 ASSERT(args.length() == 2);
11668
11669 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011670 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011671 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11672 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011673 if (!maybe_check->ToObject(&check)) return maybe_check;
11674 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011675 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11676
11677 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011678 Handle<FixedArray> details =
11679 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011680
11681 // Thread index 0 is current thread.
11682 if (index == 0) {
11683 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011684 details->set(kThreadDetailsCurrentThreadIndex,
11685 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011686 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011687 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011688 } else {
11689 // Find the thread with the requested index.
11690 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011691 ThreadState* thread =
11692 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011693 while (index != n && thread != NULL) {
11694 thread = thread->Next();
11695 n++;
11696 }
11697 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011698 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011699 }
11700
11701 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011702 details->set(kThreadDetailsCurrentThreadIndex,
11703 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011704 details->set(kThreadDetailsThreadIdIndex,
11705 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011706 }
11707
11708 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011709 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011710}
11711
11712
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011713// Sets the disable break state
11714// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011715RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011716 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011717 ASSERT(args.length() == 1);
11718 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011719 isolate->debug()->set_disable_break(disable_break);
11720 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011721}
11722
11723
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011724RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011725 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011726 ASSERT(args.length() == 1);
11727
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011728 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11729 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011730 // Find the number of break points
11731 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011732 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011733 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011734 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011735 Handle<FixedArray>::cast(break_locations));
11736}
11737
11738
11739// Set a break point in a function
11740// args[0]: function
11741// args[1]: number: break source position (within the function source)
11742// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011743RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011744 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011745 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011746 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11747 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011748 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11749 RUNTIME_ASSERT(source_position >= 0);
11750 Handle<Object> break_point_object_arg = args.at<Object>(2);
11751
11752 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011753 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11754 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011755
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011756 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011757}
11758
11759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011760Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11761 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011762 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011763 // Iterate the heap looking for SharedFunctionInfo generated from the
11764 // script. The inner most SharedFunctionInfo containing the source position
11765 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011766 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011767 // which is found is not compiled it is compiled and the heap is iterated
11768 // again as the compilation might create inner functions from the newly
11769 // compiled function and the actual requested break point might be in one of
11770 // these functions.
11771 bool done = false;
11772 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011773 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011775 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011776 { // Extra scope for iterator and no-allocation.
11777 isolate->heap()->EnsureHeapIsIterable();
11778 AssertNoAllocation no_alloc_during_heap_iteration;
11779 HeapIterator iterator;
11780 for (HeapObject* obj = iterator.next();
11781 obj != NULL; obj = iterator.next()) {
11782 if (obj->IsSharedFunctionInfo()) {
11783 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11784 if (shared->script() == *script) {
11785 // If the SharedFunctionInfo found has the requested script data and
11786 // contains the source position it is a candidate.
11787 int start_position = shared->function_token_position();
11788 if (start_position == RelocInfo::kNoPosition) {
11789 start_position = shared->start_position();
11790 }
11791 if (start_position <= position &&
11792 position <= shared->end_position()) {
11793 // If there is no candidate or this function is within the current
11794 // candidate this is the new candidate.
11795 if (target.is_null()) {
11796 target_start_position = start_position;
11797 target = shared;
11798 } else {
11799 if (target_start_position == start_position &&
11800 shared->end_position() == target->end_position()) {
11801 // If a top-level function contain only one function
11802 // declartion the source for the top-level and the
11803 // function is the same. In that case prefer the non
11804 // top-level function.
11805 if (!shared->is_toplevel()) {
11806 target_start_position = start_position;
11807 target = shared;
11808 }
11809 } else if (target_start_position <= start_position &&
11810 shared->end_position() <= target->end_position()) {
11811 // This containment check includes equality as a function
11812 // inside a top-level function can share either start or end
11813 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011814 target_start_position = start_position;
11815 target = shared;
11816 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011817 }
11818 }
11819 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011820 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011821 } // End for loop.
11822 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011823
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011824 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011825 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011826 }
11827
11828 // If the candidate found is compiled we are done. NOTE: when lazy
11829 // compilation of inner functions is introduced some additional checking
11830 // needs to be done here to compile inner functions.
11831 done = target->is_compiled();
11832 if (!done) {
11833 // If the candidate is not compiled compile it to reveal any inner
11834 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011835 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011836 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011837 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011838
11839 return *target;
11840}
11841
11842
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011843// Changes the state of a break point in a script and returns source position
11844// where break point was set. NOTE: Regarding performance see the NOTE for
11845// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011846// args[0]: script to set break point in
11847// args[1]: number: break source position (within the script source)
11848// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011849RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011850 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011851 ASSERT(args.length() == 3);
11852 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11853 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11854 RUNTIME_ASSERT(source_position >= 0);
11855 Handle<Object> break_point_object_arg = args.at<Object>(2);
11856
11857 // Get the script from the script wrapper.
11858 RUNTIME_ASSERT(wrapper->value()->IsScript());
11859 Handle<Script> script(Script::cast(wrapper->value()));
11860
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011861 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011862 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011863 if (!result->IsUndefined()) {
11864 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11865 // Find position within function. The script position might be before the
11866 // source position of the first function.
11867 int position;
11868 if (shared->start_position() > source_position) {
11869 position = 0;
11870 } else {
11871 position = source_position - shared->start_position();
11872 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011873 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011874 position += shared->start_position();
11875 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011876 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011877 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011878}
11879
11880
11881// Clear a break point
11882// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011883RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011884 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011885 ASSERT(args.length() == 1);
11886 Handle<Object> break_point_object_arg = args.at<Object>(0);
11887
11888 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011889 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011890
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011891 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011892}
11893
11894
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011895// Change the state of break on exceptions.
11896// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11897// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011898RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011899 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011900 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011901 RUNTIME_ASSERT(args[0]->IsNumber());
11902 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011903
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011904 // If the number doesn't match an enum value, the ChangeBreakOnException
11905 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011906 ExceptionBreakType type =
11907 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011908 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011909 isolate->debug()->ChangeBreakOnException(type, enable);
11910 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011911}
11912
11913
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011914// Returns the state of break on exceptions
11915// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011916RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011917 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011918 ASSERT(args.length() == 1);
11919 RUNTIME_ASSERT(args[0]->IsNumber());
11920
11921 ExceptionBreakType type =
11922 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011923 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011924 return Smi::FromInt(result);
11925}
11926
11927
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011928// Prepare for stepping
11929// args[0]: break id for checking execution state
11930// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011931// args[2]: number of times to perform the step, for step out it is the number
11932// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011933RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011934 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011935 ASSERT(args.length() == 3);
11936 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011937 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011938 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11939 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011940 if (!maybe_check->ToObject(&check)) return maybe_check;
11941 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011942 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011943 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011944 }
11945
11946 // Get the step action and check validity.
11947 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11948 if (step_action != StepIn &&
11949 step_action != StepNext &&
11950 step_action != StepOut &&
11951 step_action != StepInMin &&
11952 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011953 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011954 }
11955
11956 // Get the number of steps.
11957 int step_count = NumberToInt32(args[2]);
11958 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011959 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011960 }
11961
ager@chromium.orga1645e22009-09-09 19:27:10 +000011962 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011963 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011964
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011965 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011966 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11967 step_count);
11968 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011969}
11970
11971
11972// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011973RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011974 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011975 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011976 isolate->debug()->ClearStepping();
11977 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011978}
11979
11980
11981// Creates a copy of the with context chain. The copy of the context chain is
11982// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011983static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11984 Handle<JSFunction> function,
11985 Handle<Context> base,
11986 JavaScriptFrame* frame,
11987 int inlined_frame_index) {
11988 HandleScope scope(isolate);
11989 List<Handle<ScopeInfo> > scope_chain;
11990 List<Handle<Context> > context_chain;
11991
11992 ScopeIterator it(isolate, frame, inlined_frame_index);
11993 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11994 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11995 ASSERT(!it.Done());
11996 scope_chain.Add(it.CurrentScopeInfo());
11997 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011998 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011999
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012000 // At the end of the chain. Return the base context to link to.
12001 Handle<Context> context = base;
12002
12003 // Iteratively copy and or materialize the nested contexts.
12004 while (!scope_chain.is_empty()) {
12005 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
12006 Handle<Context> current = context_chain.RemoveLast();
12007 ASSERT(!(scope_info->HasContext() & current.is_null()));
12008
12009 if (scope_info->Type() == CATCH_SCOPE) {
12010 Handle<String> name(String::cast(current->extension()));
12011 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
12012 context =
12013 isolate->factory()->NewCatchContext(function,
12014 context,
12015 name,
12016 thrown_object);
12017 } else if (scope_info->Type() == BLOCK_SCOPE) {
12018 // Materialize the contents of the block scope into a JSObject.
12019 Handle<JSObject> block_scope_object =
12020 MaterializeBlockScope(isolate, current);
12021 if (block_scope_object.is_null()) {
12022 return Handle<Context>::null();
12023 }
12024 // Allocate a new function context for the debug evaluation and set the
12025 // extension object.
12026 Handle<Context> new_context =
12027 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12028 function);
12029 new_context->set_extension(*block_scope_object);
12030 new_context->set_previous(*context);
12031 context = new_context;
12032 } else {
12033 ASSERT(scope_info->Type() == WITH_SCOPE);
12034 ASSERT(current->IsWithContext());
12035 Handle<JSObject> extension(JSObject::cast(current->extension()));
12036 context =
12037 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000012038 }
erikcorry0ad885c2011-11-21 13:51:57 +000012039 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012040
12041 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012042}
12043
12044
12045// Helper function to find or create the arguments object for
12046// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012047static Handle<Object> GetArgumentsObject(Isolate* isolate,
12048 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012049 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012050 Handle<JSFunction> function,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012051 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012052 Handle<Context> function_context) {
12053 // Try to find the value of 'arguments' to pass as parameter. If it is not
12054 // found (that is the debugged function does not reference 'arguments' and
12055 // does not support eval) then create an 'arguments' object.
12056 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012057 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012058 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012059 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012060 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012061 }
12062 }
12063
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012064 if (scope_info->HasHeapAllocatedLocals()) {
12065 VariableMode mode;
12066 InitializationFlag init_flag;
12067 index = scope_info->ContextSlotIndex(
12068 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012069 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012070 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012071 }
12072 }
12073
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012074 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
12075
12076 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012077 Handle<JSObject> arguments =
12078 isolate->factory()->NewArgumentsObject(function, length);
12079 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012080
12081 AssertNoAllocation no_gc;
12082 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012083 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012084 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012085 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012086 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012087 return arguments;
12088}
12089
12090
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012091static const char kSourceStr[] =
12092 "(function(arguments,__source__){return eval(__source__);})";
12093
12094
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012095// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012096// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012097// extension part has all the parameters and locals of the function on the
12098// stack frame. A function which calls eval with the code to evaluate is then
12099// compiled in this context and called in this context. As this context
12100// replaces the context of the function on the stack frame a new (empty)
12101// function is created as well to be used as the closure for the context.
12102// This function and the context acts as replacements for the function on the
12103// stack frame presenting the same view of the values of parameters and
12104// local variables as if the piece of JavaScript was evaluated at the point
12105// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012106RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012107 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012108
12109 // Check the execution state and decode arguments frame and source to be
12110 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012111 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012112 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012113 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12114 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012115 if (!maybe_check_result->ToObject(&check_result)) {
12116 return maybe_check_result;
12117 }
12118 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012119 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012120 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
12121 CONVERT_ARG_CHECKED(String, source, 3);
12122 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12123 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012124
12125 // Handle the processing of break.
12126 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012127
12128 // Get the frame where the debugging is performed.
12129 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012130 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012131 JavaScriptFrame* frame = it.frame();
12132 Handle<JSFunction> function(JSFunction::cast(frame->function()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012133 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012134
12135 // Traverse the saved contexts chain to find the active context for the
12136 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012137 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012139 SaveContext savex(isolate);
12140 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012141
12142 // Create the (empty) function replacing the function on the stack frame for
12143 // the purpose of evaluating in the context created below. It is important
12144 // that this function does not describe any parameters and local variables
12145 // in the context. If it does then this will cause problems with the lookup
12146 // in Context::Lookup, where context slots for parameters and local variables
12147 // are looked at before the extension object.
12148 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012149 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12150 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012151 go_between->set_context(function->context());
12152#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012153 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12154 ASSERT(go_between_scope_info->ParameterCount() == 0);
12155 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012156#endif
12157
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012158 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012159 Handle<JSObject> local_scope = MaterializeLocalScope(
12160 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012161 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012162
12163 // Allocate a new context for the debug evaluation and set the extension
12164 // object build.
12165 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012166 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12167 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012168 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012169 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012170 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012171 Handle<Context> function_context;
12172 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012173 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012174 function_context = Handle<Context>(frame_context->declaration_context());
12175 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012176 context = CopyNestedScopeContextChain(isolate,
12177 go_between,
12178 context,
12179 frame,
12180 inlined_frame_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012181
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012182 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012183 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012184 context =
12185 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012186 }
12187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012188 // Wrap the evaluation statement in a new function compiled in the newly
12189 // created context. The function has one parameter which has to be called
12190 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012191 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012192 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012193
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012194 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012195 isolate->factory()->NewStringFromAscii(
12196 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012197
12198 // Currently, the eval code will be executed in non-strict mode,
12199 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012200 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012201 Compiler::CompileEval(function_source,
12202 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012203 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012204 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012205 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012206 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012207 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012208 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012209
12210 // Invoke the result of the compilation to get the evaluation function.
12211 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012212 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012213 Handle<Object> evaluation_function =
12214 Execution::Call(compiled_function, receiver, 0, NULL,
12215 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012216 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012217
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012218 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012219 frame,
12220 inlined_frame_index,
12221 function,
12222 scope_info,
12223 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012224
12225 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012226 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012227 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012228 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12229 receiver,
12230 ARRAY_SIZE(argv),
12231 argv,
12232 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012233 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012234
12235 // Skip the global proxy as it has no properties and always delegates to the
12236 // real global object.
12237 if (result->IsJSGlobalProxy()) {
12238 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12239 }
12240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012241 return *result;
12242}
12243
12244
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012245RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012246 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012247
12248 // Check the execution state and decode arguments frame and source to be
12249 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012250 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012251 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012252 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12253 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012254 if (!maybe_check_result->ToObject(&check_result)) {
12255 return maybe_check_result;
12256 }
12257 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012258 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012259 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012260 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012261
12262 // Handle the processing of break.
12263 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012264
12265 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012266 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012267 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012268 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269 top = top->prev();
12270 }
12271 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012272 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012273 }
12274
12275 // Get the global context now set to the top context from before the
12276 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012277 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012278
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012279 bool is_global = true;
12280
12281 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012282 // Create a new with context with the additional context information between
12283 // the context of the debugged function and the eval code to be executed.
12284 context = isolate->factory()->NewWithContext(
12285 Handle<JSFunction>(context->closure()),
12286 context,
12287 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012288 is_global = false;
12289 }
12290
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012291 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012292 // Currently, the eval code will be executed in non-strict mode,
12293 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012294 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012295 Compiler::CompileEval(source,
12296 context,
12297 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012298 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012299 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012300 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012301 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012302 Handle<JSFunction>(
12303 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12304 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012305
12306 // Invoke the result of the compilation to get the evaluation function.
12307 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012308 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012309 Handle<Object> result =
12310 Execution::Call(compiled_function, receiver, 0, NULL,
12311 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012312 // Clear the oneshot breakpoints so that the debugger does not step further.
12313 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012314 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012315 return *result;
12316}
12317
12318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012319RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012320 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012321 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012322
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012323 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012324 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012325
12326 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012327 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012328 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12329 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12330 // because using
12331 // instances->set(i, *GetScriptWrapper(script))
12332 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012333 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012334 Handle<JSValue> wrapper = GetScriptWrapper(script);
12335 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012336 }
12337
12338 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012339 Handle<JSObject> result =
12340 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012341 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012342 return *result;
12343}
12344
12345
12346// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012347static int DebugReferencedBy(HeapIterator* iterator,
12348 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012349 Object* instance_filter, int max_references,
12350 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012351 JSFunction* arguments_function) {
12352 NoHandleAllocation ha;
12353 AssertNoAllocation no_alloc;
12354
12355 // Iterate the heap.
12356 int count = 0;
12357 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012358 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012359 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012360 (max_references == 0 || count < max_references)) {
12361 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012362 if (heap_obj->IsJSObject()) {
12363 // Skip context extension objects and argument arrays as these are
12364 // checked in the context of functions using them.
12365 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012366 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012367 obj->map()->constructor() == arguments_function) {
12368 continue;
12369 }
12370
12371 // Check if the JS object has a reference to the object looked for.
12372 if (obj->ReferencesObject(target)) {
12373 // Check instance filter if supplied. This is normally used to avoid
12374 // references from mirror objects (see Runtime_IsInPrototypeChain).
12375 if (!instance_filter->IsUndefined()) {
12376 Object* V = obj;
12377 while (true) {
12378 Object* prototype = V->GetPrototype();
12379 if (prototype->IsNull()) {
12380 break;
12381 }
12382 if (instance_filter == prototype) {
12383 obj = NULL; // Don't add this object.
12384 break;
12385 }
12386 V = prototype;
12387 }
12388 }
12389
12390 if (obj != NULL) {
12391 // Valid reference found add to instance array if supplied an update
12392 // count.
12393 if (instances != NULL && count < instances_size) {
12394 instances->set(count, obj);
12395 }
12396 last = obj;
12397 count++;
12398 }
12399 }
12400 }
12401 }
12402
12403 // Check for circular reference only. This can happen when the object is only
12404 // referenced from mirrors and has a circular reference in which case the
12405 // object is not really alive and would have been garbage collected if not
12406 // referenced from the mirror.
12407 if (count == 1 && last == target) {
12408 count = 0;
12409 }
12410
12411 // Return the number of referencing objects found.
12412 return count;
12413}
12414
12415
12416// Scan the heap for objects with direct references to an object
12417// args[0]: the object to find references to
12418// args[1]: constructor function for instances to exclude (Mirror)
12419// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012420RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012421 ASSERT(args.length() == 3);
12422
12423 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012424 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12425 // The heap iterator reserves the right to do a GC to make the heap iterable.
12426 // Due to the GC above we know it won't need to do that, but it seems cleaner
12427 // to get the heap iterator constructed before we start having unprotected
12428 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012429
12430 // Check parameters.
12431 CONVERT_CHECKED(JSObject, target, args[0]);
12432 Object* instance_filter = args[1];
12433 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12434 instance_filter->IsJSObject());
12435 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12436 RUNTIME_ASSERT(max_references >= 0);
12437
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012439 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012440 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012441 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012442 JSFunction* arguments_function =
12443 JSFunction::cast(arguments_boilerplate->map()->constructor());
12444
12445 // Get the number of referencing objects.
12446 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012447 HeapIterator heap_iterator;
12448 count = DebugReferencedBy(&heap_iterator,
12449 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012450 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012451
12452 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012453 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012454 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012455 if (!maybe_object->ToObject(&object)) return maybe_object;
12456 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012457 FixedArray* instances = FixedArray::cast(object);
12458
12459 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012460 // AllocateFixedArray above does not make the heap non-iterable.
12461 ASSERT(HEAP->IsHeapIterable());
12462 HeapIterator heap_iterator2;
12463 count = DebugReferencedBy(&heap_iterator2,
12464 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012465 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012466
12467 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012468 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012469 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012470 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012471 if (!maybe_result->ToObject(&result)) return maybe_result;
12472 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012473}
12474
12475
12476// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012477static int DebugConstructedBy(HeapIterator* iterator,
12478 JSFunction* constructor,
12479 int max_references,
12480 FixedArray* instances,
12481 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012482 AssertNoAllocation no_alloc;
12483
12484 // Iterate the heap.
12485 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012486 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012487 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012488 (max_references == 0 || count < max_references)) {
12489 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012490 if (heap_obj->IsJSObject()) {
12491 JSObject* obj = JSObject::cast(heap_obj);
12492 if (obj->map()->constructor() == constructor) {
12493 // Valid reference found add to instance array if supplied an update
12494 // count.
12495 if (instances != NULL && count < instances_size) {
12496 instances->set(count, obj);
12497 }
12498 count++;
12499 }
12500 }
12501 }
12502
12503 // Return the number of referencing objects found.
12504 return count;
12505}
12506
12507
12508// Scan the heap for objects constructed by a specific function.
12509// args[0]: the constructor to find instances of
12510// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012511RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012512 ASSERT(args.length() == 2);
12513
12514 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012515 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012516
12517 // Check parameters.
12518 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12519 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12520 RUNTIME_ASSERT(max_references >= 0);
12521
12522 // Get the number of referencing objects.
12523 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012524 HeapIterator heap_iterator;
12525 count = DebugConstructedBy(&heap_iterator,
12526 constructor,
12527 max_references,
12528 NULL,
12529 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012530
12531 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012532 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012533 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012534 if (!maybe_object->ToObject(&object)) return maybe_object;
12535 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012536 FixedArray* instances = FixedArray::cast(object);
12537
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012538 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012539 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012540 HeapIterator heap_iterator2;
12541 count = DebugConstructedBy(&heap_iterator2,
12542 constructor,
12543 max_references,
12544 instances,
12545 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012546
12547 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012548 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012549 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12550 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012551 if (!maybe_result->ToObject(&result)) return maybe_result;
12552 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012553 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012554}
12555
12556
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012557// Find the effective prototype object as returned by __proto__.
12558// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012559RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012560 ASSERT(args.length() == 1);
12561
12562 CONVERT_CHECKED(JSObject, obj, args[0]);
12563
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012564 // Use the __proto__ accessor.
12565 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012566}
12567
12568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012569RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012570 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012571 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012572 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012573}
12574
12575
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012576RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012577#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012578 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012579 ASSERT(args.length() == 1);
12580 // Get the function and make sure it is compiled.
12581 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012582 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012583 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012584 return Failure::Exception();
12585 }
12586 func->code()->PrintLn();
12587#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012588 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012589}
ager@chromium.org9085a012009-05-11 19:22:57 +000012590
12591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012592RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012593#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012594 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012595 ASSERT(args.length() == 1);
12596 // Get the function and make sure it is compiled.
12597 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012598 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012599 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012600 return Failure::Exception();
12601 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012602 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012603#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012604 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012605}
12606
12607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012608RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012609 NoHandleAllocation ha;
12610 ASSERT(args.length() == 1);
12611
12612 CONVERT_CHECKED(JSFunction, f, args[0]);
12613 return f->shared()->inferred_name();
12614}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012615
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012616
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012617static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12618 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012619 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012620 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012621 int counter = 0;
12622 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012623 for (HeapObject* obj = iterator->next();
12624 obj != NULL;
12625 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012626 ASSERT(obj != NULL);
12627 if (!obj->IsSharedFunctionInfo()) {
12628 continue;
12629 }
12630 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12631 if (shared->script() != script) {
12632 continue;
12633 }
12634 if (counter < buffer_size) {
12635 buffer->set(counter, shared);
12636 }
12637 counter++;
12638 }
12639 return counter;
12640}
12641
12642// For a script finds all SharedFunctionInfo's in the heap that points
12643// to this script. Returns JSArray of SharedFunctionInfo wrapped
12644// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012645RUNTIME_FUNCTION(MaybeObject*,
12646 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012647 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012648 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012649 CONVERT_CHECKED(JSValue, script_value, args[0]);
12650
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012651
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012652 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12653
12654 const int kBufferSize = 32;
12655
12656 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012657 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012658 int number;
12659 {
12660 isolate->heap()->EnsureHeapIsIterable();
12661 AssertNoAllocation no_allocations;
12662 HeapIterator heap_iterator;
12663 Script* scr = *script;
12664 FixedArray* arr = *array;
12665 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12666 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012667 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012668 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012669 isolate->heap()->EnsureHeapIsIterable();
12670 AssertNoAllocation no_allocations;
12671 HeapIterator heap_iterator;
12672 Script* scr = *script;
12673 FixedArray* arr = *array;
12674 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012675 }
12676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012677 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012678 result->set_length(Smi::FromInt(number));
12679
12680 LiveEdit::WrapSharedFunctionInfos(result);
12681
12682 return *result;
12683}
12684
12685// For a script calculates compilation information about all its functions.
12686// The script source is explicitly specified by the second argument.
12687// The source of the actual script is not used, however it is important that
12688// all generated code keeps references to this particular instance of script.
12689// Returns a JSArray of compilation infos. The array is ordered so that
12690// each function with all its descendant is always stored in a continues range
12691// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012692RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012693 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012694 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012695 CONVERT_CHECKED(JSValue, script, args[0]);
12696 CONVERT_ARG_CHECKED(String, source, 1);
12697 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12698
12699 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12700
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012701 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012702 return Failure::Exception();
12703 }
12704
12705 return result;
12706}
12707
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012708// Changes the source of the script to a new_source.
12709// If old_script_name is provided (i.e. is a String), also creates a copy of
12710// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012711RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012712 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012713 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012714 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12715 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012716 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012717
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012718 CONVERT_CHECKED(Script, original_script_pointer,
12719 original_script_value->value());
12720 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012721
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012722 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12723 new_source,
12724 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012725
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012726 if (old_script->IsScript()) {
12727 Handle<Script> script_handle(Script::cast(old_script));
12728 return *(GetScriptWrapper(script_handle));
12729 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012730 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012731 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012732}
12733
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012734
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012735RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012736 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012737 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012738 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12739 return LiveEdit::FunctionSourceUpdated(shared_info);
12740}
12741
12742
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012743// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012744RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012745 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012746 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012747 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12748 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12749
ager@chromium.orgac091b72010-05-05 07:34:42 +000012750 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012751}
12752
12753// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012754RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012755 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012756 HandleScope scope(isolate);
12757 Handle<Object> function_object(args[0], isolate);
12758 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012759
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012760 if (function_object->IsJSValue()) {
12761 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12762 if (script_object->IsJSValue()) {
12763 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012764 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012765 }
12766
12767 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12768 } else {
12769 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12770 // and we check it in this function.
12771 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012772
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012773 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012774}
12775
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012776
12777// In a code of a parent function replaces original function as embedded object
12778// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012779RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012780 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012781 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012782
12783 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12784 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12785 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12786
12787 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12788 subst_wrapper);
12789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012790 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012791}
12792
12793
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012794// Updates positions of a shared function info (first parameter) according
12795// to script source change. Text change is described in second parameter as
12796// array of groups of 3 numbers:
12797// (change_begin, change_end, change_end_new_position).
12798// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012799RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012800 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012801 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012802 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12803 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12804
ager@chromium.orgac091b72010-05-05 07:34:42 +000012805 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012806}
12807
12808
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012809// For array of SharedFunctionInfo's (each wrapped in JSValue)
12810// checks that none of them have activations on stacks (of any thread).
12811// Returns array of the same length with corresponding results of
12812// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012813RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012814 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012815 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012816 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012817 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012818
ager@chromium.org357bf652010-04-12 11:30:10 +000012819 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012820}
12821
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012822// Compares 2 strings line-by-line, then token-wise and returns diff in form
12823// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12824// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012825RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012826 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012827 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012828 CONVERT_ARG_CHECKED(String, s1, 0);
12829 CONVERT_ARG_CHECKED(String, s2, 1);
12830
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012831 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012832}
12833
12834
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012835// A testing entry. Returns statement position which is the closest to
12836// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012837RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012838 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012839 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012840 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12841 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12842
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012843 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012844
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012845 if (code->kind() != Code::FUNCTION &&
12846 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012847 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012848 }
12849
12850 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012851 int closest_pc = 0;
12852 int distance = kMaxInt;
12853 while (!it.done()) {
12854 int statement_position = static_cast<int>(it.rinfo()->data());
12855 // Check if this break point is closer that what was previously found.
12856 if (source_position <= statement_position &&
12857 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012858 closest_pc =
12859 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012860 distance = statement_position - source_position;
12861 // Check whether we can't get any closer.
12862 if (distance == 0) break;
12863 }
12864 it.next();
12865 }
12866
12867 return Smi::FromInt(closest_pc);
12868}
12869
12870
ager@chromium.org357bf652010-04-12 11:30:10 +000012871// Calls specified function with or without entering the debugger.
12872// This is used in unit tests to run code as if debugger is entered or simply
12873// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012874RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012875 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012876 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012877 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12878 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12879
12880 Handle<Object> result;
12881 bool pending_exception;
12882 {
12883 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012884 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012885 &pending_exception);
12886 } else {
12887 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012888 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012889 &pending_exception);
12890 }
12891 }
12892 if (!pending_exception) {
12893 return *result;
12894 } else {
12895 return Failure::Exception();
12896 }
12897}
12898
12899
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012900// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012901RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012902 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012903 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012904 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12905 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012906 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012907}
12908
12909
12910// Performs a GC.
12911// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012912RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012913 isolate->heap()->CollectAllGarbage(true);
12914 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012915}
12916
12917
12918// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012919RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012920 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012921 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012922 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012923 }
12924 return Smi::FromInt(usage);
12925}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012926
12927
12928// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012929RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012930#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012931 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012932#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012933 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012934#endif
12935}
12936
12937
12938// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012939RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012940#ifdef LIVE_OBJECT_LIST
12941 return LiveObjectList::Capture();
12942#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012943 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012944#endif
12945}
12946
12947
12948// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012949RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012950#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012951 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012952 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012953 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012954#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012955 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012956#endif
12957}
12958
12959
12960// Generates the response to a debugger request for a dump of the objects
12961// contained in the difference between the captured live object lists
12962// specified by id1 and id2.
12963// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12964// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012965RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012966#ifdef LIVE_OBJECT_LIST
12967 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012968 CONVERT_SMI_ARG_CHECKED(id1, 0);
12969 CONVERT_SMI_ARG_CHECKED(id2, 1);
12970 CONVERT_SMI_ARG_CHECKED(start, 2);
12971 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012972 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12973 EnterDebugger enter_debugger;
12974 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12975#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012976 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012977#endif
12978}
12979
12980
12981// Gets the specified object as requested by the debugger.
12982// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012983RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012984#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012985 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012986 Object* result = LiveObjectList::GetObj(obj_id);
12987 return result;
12988#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012989 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012990#endif
12991}
12992
12993
12994// Gets the obj id for the specified address if valid.
12995// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012996RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012997#ifdef LIVE_OBJECT_LIST
12998 HandleScope scope;
12999 CONVERT_ARG_CHECKED(String, address, 0);
13000 Object* result = LiveObjectList::GetObjId(address);
13001 return result;
13002#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013003 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013004#endif
13005}
13006
13007
13008// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013009RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013010#ifdef LIVE_OBJECT_LIST
13011 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013012 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013013 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
13014 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
13015 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
13016 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
13017 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
13018
13019 Handle<JSObject> instance_filter;
13020 if (args[1]->IsJSObject()) {
13021 instance_filter = args.at<JSObject>(1);
13022 }
13023 bool verbose = false;
13024 if (args[2]->IsBoolean()) {
13025 verbose = args[2]->IsTrue();
13026 }
13027 int start = 0;
13028 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013029 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013030 }
13031 int limit = Smi::kMaxValue;
13032 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013033 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013034 }
13035
13036 return LiveObjectList::GetObjRetainers(obj_id,
13037 instance_filter,
13038 verbose,
13039 start,
13040 limit,
13041 filter_obj);
13042#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013043 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013044#endif
13045}
13046
13047
13048// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013049RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013050#ifdef LIVE_OBJECT_LIST
13051 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013052 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13053 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013054 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13055
13056 Handle<JSObject> instance_filter;
13057 if (args[2]->IsJSObject()) {
13058 instance_filter = args.at<JSObject>(2);
13059 }
13060
13061 Object* result =
13062 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13063 return result;
13064#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013065 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013066#endif
13067}
13068
13069
13070// Generates the response to a debugger request for a list of all
13071// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013072RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013073#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013074 CONVERT_SMI_ARG_CHECKED(start, 0);
13075 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013076 return LiveObjectList::Info(start, count);
13077#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013078 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013079#endif
13080}
13081
13082
13083// Gets a dump of the specified object as requested by the debugger.
13084// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013085RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013086#ifdef LIVE_OBJECT_LIST
13087 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013088 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013089 Object* result = LiveObjectList::PrintObj(obj_id);
13090 return result;
13091#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013092 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013093#endif
13094}
13095
13096
13097// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013098RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013099#ifdef LIVE_OBJECT_LIST
13100 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013101 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013102#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013103 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013104#endif
13105}
13106
13107
13108// Generates the response to a debugger request for a summary of the types
13109// of objects in the difference between the captured live object lists
13110// specified by id1 and id2.
13111// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13112// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013113RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013114#ifdef LIVE_OBJECT_LIST
13115 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013116 CONVERT_SMI_ARG_CHECKED(id1, 0);
13117 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013118 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13119
13120 EnterDebugger enter_debugger;
13121 return LiveObjectList::Summarize(id1, id2, filter_obj);
13122#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013123 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013124#endif
13125}
13126
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013127#endif // ENABLE_DEBUGGER_SUPPORT
13128
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013129
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013130RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013131 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013132 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013133 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013134}
13135
13136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013137RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013138 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013139 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013140 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013141}
13142
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013144// Finds the script object from the script data. NOTE: This operation uses
13145// heap traversal to find the function generated for the source position
13146// for the requested break point. For lazily compiled functions several heap
13147// traversals might be required rendering this operation as a rather slow
13148// operation. However for setting break points which is normally done through
13149// some kind of user interaction the performance is not crucial.
13150static Handle<Object> Runtime_GetScriptFromScriptName(
13151 Handle<String> script_name) {
13152 // Scan the heap for Script objects to find the script with the requested
13153 // script data.
13154 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013155 script_name->GetHeap()->EnsureHeapIsIterable();
13156 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013157 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013158 HeapObject* obj = NULL;
13159 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013160 // If a script is found check if it has the script data requested.
13161 if (obj->IsScript()) {
13162 if (Script::cast(obj)->name()->IsString()) {
13163 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13164 script = Handle<Script>(Script::cast(obj));
13165 }
13166 }
13167 }
13168 }
13169
13170 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013171 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013172
13173 // Return the script found.
13174 return GetScriptWrapper(script);
13175}
13176
13177
13178// Get the script object from script data. NOTE: Regarding performance
13179// see the NOTE for GetScriptFromScriptData.
13180// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013181RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013182 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013183
13184 ASSERT(args.length() == 1);
13185
13186 CONVERT_CHECKED(String, script_name, args[0]);
13187
13188 // Find the requested script.
13189 Handle<Object> result =
13190 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13191 return *result;
13192}
13193
13194
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013195// Determines whether the given stack frame should be displayed in
13196// a stack trace. The caller is the error constructor that asked
13197// for the stack trace to be collected. The first time a construct
13198// call to this function is encountered it is skipped. The seen_caller
13199// in/out parameter is used to remember if the caller has been seen
13200// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013201static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13202 Object* caller,
13203 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013204 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013205 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013206 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013207 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013208 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13209 Object* raw_fun = frame->function();
13210 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013211 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013212 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013213 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013214 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013215 *seen_caller = true;
13216 return false;
13217 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013218 // Skip all frames until we've seen the caller.
13219 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013220 // Also, skip non-visible built-in functions and any call with the builtins
13221 // object as receiver, so as to not reveal either the builtins object or
13222 // an internal function.
13223 // The --builtins-in-stack-traces command line flag allows including
13224 // internal call sites in the stack trace for debugging purposes.
13225 if (!FLAG_builtins_in_stack_traces) {
13226 JSFunction* fun = JSFunction::cast(raw_fun);
13227 if (frame->receiver()->IsJSBuiltinsObject() ||
13228 (fun->IsBuiltin() && !fun->shared()->native())) {
13229 return false;
13230 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013231 }
13232 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013233}
13234
13235
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013236// Collect the raw data for a stack trace. Returns an array of 4
13237// element segments each containing a receiver, function, code and
13238// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013239RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013240 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013241 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013242 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013244 HandleScope scope(isolate);
13245 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013246
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013247 limit = Max(limit, 0); // Ensure that limit is not negative.
13248 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013249 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013250 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013251
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013252 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013253 // If the caller parameter is a function we skip frames until we're
13254 // under it before starting to collect.
13255 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013256 int cursor = 0;
13257 int frames_seen = 0;
13258 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013259 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013260 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013261 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013262 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013263 // Set initial size to the maximum inlining level + 1 for the outermost
13264 // function.
13265 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013266 frame->Summarize(&frames);
13267 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013268 if (cursor + 4 > elements->length()) {
13269 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13270 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013271 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013272 for (int i = 0; i < cursor; i++) {
13273 new_elements->set(i, elements->get(i));
13274 }
13275 elements = new_elements;
13276 }
13277 ASSERT(cursor + 4 <= elements->length());
13278
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013279 Handle<Object> recv = frames[i].receiver();
13280 Handle<JSFunction> fun = frames[i].function();
13281 Handle<Code> code = frames[i].code();
13282 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013283 elements->set(cursor++, *recv);
13284 elements->set(cursor++, *fun);
13285 elements->set(cursor++, *code);
13286 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013287 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013288 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013289 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013290 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013291 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013292 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013293 return *result;
13294}
13295
13296
ager@chromium.org3811b432009-10-28 14:53:37 +000013297// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013298RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013299 ASSERT_EQ(args.length(), 0);
13300
13301 NoHandleAllocation ha;
13302
13303 const char* version_string = v8::V8::GetVersion();
13304
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013305 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13306 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013307}
13308
13309
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013310RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013311 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013312 OS::PrintError("abort: %s\n",
13313 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013314 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013315 OS::Abort();
13316 UNREACHABLE();
13317 return NULL;
13318}
13319
13320
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013321RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013322 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013323 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013324 Object* key = args[1];
13325
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013326 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013327 Object* o = cache->get(finger_index);
13328 if (o == key) {
13329 // The fastest case: hit the same place again.
13330 return cache->get(finger_index + 1);
13331 }
13332
13333 for (int i = finger_index - 2;
13334 i >= JSFunctionResultCache::kEntriesIndex;
13335 i -= 2) {
13336 o = cache->get(i);
13337 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013338 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013339 return cache->get(i + 1);
13340 }
13341 }
13342
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013343 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013344 ASSERT(size <= cache->length());
13345
13346 for (int i = size - 2; i > finger_index; i -= 2) {
13347 o = cache->get(i);
13348 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013349 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013350 return cache->get(i + 1);
13351 }
13352 }
13353
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013354 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013355 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013356
13357 Handle<JSFunctionResultCache> cache_handle(cache);
13358 Handle<Object> key_handle(key);
13359 Handle<Object> value;
13360 {
13361 Handle<JSFunction> factory(JSFunction::cast(
13362 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13363 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013364 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013365 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013366 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013367 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013368 value = Execution::Call(factory,
13369 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013370 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013371 argv,
13372 &pending_exception);
13373 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013374 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013375
13376#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013377 if (FLAG_verify_heap) {
13378 cache_handle->JSFunctionResultCacheVerify();
13379 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013380#endif
13381
13382 // Function invocation may have cleared the cache. Reread all the data.
13383 finger_index = cache_handle->finger_index();
13384 size = cache_handle->size();
13385
13386 // If we have spare room, put new data into it, otherwise evict post finger
13387 // entry which is likely to be the least recently used.
13388 int index = -1;
13389 if (size < cache_handle->length()) {
13390 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13391 index = size;
13392 } else {
13393 index = finger_index + JSFunctionResultCache::kEntrySize;
13394 if (index == cache_handle->length()) {
13395 index = JSFunctionResultCache::kEntriesIndex;
13396 }
13397 }
13398
13399 ASSERT(index % 2 == 0);
13400 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13401 ASSERT(index < cache_handle->length());
13402
13403 cache_handle->set(index, *key_handle);
13404 cache_handle->set(index + 1, *value);
13405 cache_handle->set_finger_index(index);
13406
13407#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013408 if (FLAG_verify_heap) {
13409 cache_handle->JSFunctionResultCacheVerify();
13410 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013411#endif
13412
13413 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013414}
13415
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013417RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013418 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013419 CONVERT_ARG_CHECKED(String, type, 0);
13420 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013421 return *isolate->factory()->NewJSMessageObject(
13422 type,
13423 arguments,
13424 0,
13425 0,
13426 isolate->factory()->undefined_value(),
13427 isolate->factory()->undefined_value(),
13428 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013429}
13430
13431
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013432RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013433 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13434 return message->type();
13435}
13436
13437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013438RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013439 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13440 return message->arguments();
13441}
13442
13443
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013444RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013445 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13446 return Smi::FromInt(message->start_position());
13447}
13448
13449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013450RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013451 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13452 return message->script();
13453}
13454
13455
kasper.lund44510672008-07-25 07:37:58 +000013456#ifdef DEBUG
13457// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13458// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013459RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013460 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013461 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013462#define COUNT_ENTRY(Name, argc, ressize) + 1
13463 int entry_count = 0
13464 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13465 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13466 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13467#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013468 Factory* factory = isolate->factory();
13469 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013470 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013471 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013472#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013473 { \
13474 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013475 Handle<String> name; \
13476 /* Inline runtime functions have an underscore in front of the name. */ \
13477 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013478 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013479 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13480 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013481 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013482 Vector<const char>(#Name, StrLength(#Name))); \
13483 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013484 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013485 pair_elements->set(0, *name); \
13486 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013487 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013488 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013489 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013490 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013491 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013492 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013493 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013494 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013495#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013496 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013497 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013498 return *result;
13499}
kasper.lund44510672008-07-25 07:37:58 +000013500#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013501
13502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013503RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013504 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013505 CONVERT_CHECKED(String, format, args[0]);
13506 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013507 String::FlatContent format_content = format->GetFlatContent();
13508 RUNTIME_ASSERT(format_content.IsAscii());
13509 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013510 LOGGER->LogRuntime(chars, elms);
13511 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013512}
13513
13514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013515RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013516 UNREACHABLE(); // implemented as macro in the parser
13517 return NULL;
13518}
13519
13520
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013521#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13522 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13523 CONVERT_CHECKED(JSObject, obj, args[0]); \
13524 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13525 }
13526
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013527ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013528ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13529ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13530ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13531ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13532ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13533ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13534ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13535ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13536ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13537ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13538ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13539ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13540ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13541
13542#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13543
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013544
13545RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13546 ASSERT(args.length() == 2);
13547 CONVERT_CHECKED(JSObject, obj1, args[0]);
13548 CONVERT_CHECKED(JSObject, obj2, args[1]);
13549 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13550}
13551
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013552// ----------------------------------------------------------------------------
13553// Implementation of Runtime
13554
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013555#define F(name, number_of_args, result_size) \
13556 { Runtime::k##name, Runtime::RUNTIME, #name, \
13557 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013558
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013559
13560#define I(name, number_of_args, result_size) \
13561 { Runtime::kInline##name, Runtime::INLINE, \
13562 "_" #name, NULL, number_of_args, result_size },
13563
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013564static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013565 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013566 INLINE_FUNCTION_LIST(I)
13567 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013568};
13569
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013570
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013571MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13572 Object* dictionary) {
13573 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013574 ASSERT(dictionary != NULL);
13575 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13576 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013577 Object* name_symbol;
13578 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013579 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013580 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13581 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013582 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013583 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13584 String::cast(name_symbol),
13585 Smi::FromInt(i),
13586 PropertyDetails(NONE, NORMAL));
13587 if (!maybe_dictionary->ToObject(&dictionary)) {
13588 // Non-recoverable failure. Calling code must restart heap
13589 // initialization.
13590 return maybe_dictionary;
13591 }
13592 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013593 }
13594 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013595}
13596
13597
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013598const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13599 Heap* heap = name->GetHeap();
13600 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013601 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013602 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013603 int function_index = Smi::cast(smi_index)->value();
13604 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013605 }
13606 return NULL;
13607}
13608
13609
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013610const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013611 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13612}
13613
13614
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013615void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013616 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013617 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013618 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013619 if (isolate->heap()->new_space()->AddFreshPage()) {
13620 return;
13621 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013622 // Try to do a garbage collection; ignore it if it fails. The C
13623 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013624 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013625 } else {
13626 // Handle last resort GC and make sure to allow future allocations
13627 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013628 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013629 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013630 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013631}
13632
13633
13634} } // namespace v8::internal