blob: 24e7bc9f2b54c1bf13531eb943d2ed574e09f822 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000119MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
120 JSObject* boilerplate) {
121 StackLimitCheck check(isolate);
122 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000125 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000127 if (!maybe_result->ToObject(&result)) return maybe_result;
128 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000129 JSObject* copy = JSObject::cast(result);
130
131 // Deep copy local properties.
132 if (copy->HasFastProperties()) {
133 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 for (int i = 0; i < properties->length(); i++) {
135 Object* value = properties->get(i);
136 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000139 if (!maybe_result->ToObject(&result)) return maybe_result;
140 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000141 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000142 }
143 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000144 int nof = copy->map()->inobject_properties();
145 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 Object* value = copy->InObjectPropertyAt(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 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 }
154 }
155 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000156 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000158 if (!maybe_result->ToObject(&result)) return maybe_result;
159 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000160 FixedArray* names = FixedArray::cast(result);
161 copy->GetLocalPropertyNames(names, 0);
162 for (int i = 0; i < names->length(); i++) {
163 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000164 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000165 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000166 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000167 // Only deep copy fields from the object literal expression.
168 // In particular, don't try to copy the length attribute of
169 // an array.
170 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000171 Object* value =
172 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000174 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000175 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000176 if (!maybe_result->ToObject(&result)) return maybe_result;
177 }
178 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000179 // Creating object copy for literals. No strict mode needed.
180 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000181 if (!maybe_result->ToObject(&result)) return maybe_result;
182 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000183 }
184 }
185 }
186
187 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000188 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000189 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000190 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000191 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000192 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000193 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000194 if (elements->map() == heap->fixed_cow_array_map()) {
195 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000196#ifdef DEBUG
197 for (int i = 0; i < elements->length(); i++) {
198 ASSERT(!elements->get(i)->IsJSObject());
199 }
200#endif
201 } else {
202 for (int i = 0; i < elements->length(); i++) {
203 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000204 ASSERT(value->IsSmi() ||
205 value->IsTheHole() ||
206 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000207 if (value->IsJSObject()) {
208 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000209 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
210 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000211 if (!maybe_result->ToObject(&result)) return maybe_result;
212 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000213 elements->set(i, result);
214 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000215 }
216 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000217 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000218 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000219 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000220 NumberDictionary* element_dictionary = copy->element_dictionary();
221 int capacity = element_dictionary->Capacity();
222 for (int i = 0; i < capacity; i++) {
223 Object* k = element_dictionary->KeyAt(i);
224 if (element_dictionary->IsKey(k)) {
225 Object* value = element_dictionary->ValueAt(i);
226 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000227 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000228 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
229 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000230 if (!maybe_result->ToObject(&result)) return maybe_result;
231 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000232 element_dictionary->ValueAtPut(i, result);
233 }
234 }
235 }
236 break;
237 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000238 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000239 UNIMPLEMENTED();
240 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000241 case EXTERNAL_PIXEL_ELEMENTS:
242 case EXTERNAL_BYTE_ELEMENTS:
243 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
244 case EXTERNAL_SHORT_ELEMENTS:
245 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
246 case EXTERNAL_INT_ELEMENTS:
247 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
248 case EXTERNAL_FLOAT_ELEMENTS:
249 case EXTERNAL_DOUBLE_ELEMENTS:
250 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000251 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000252 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000253 }
254 return copy;
255}
256
257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000258RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000259 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000260 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000261}
262
263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000264RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000265 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000266 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000267}
268
269
ager@chromium.org236ad962008-09-25 09:45:57 +0000270static Handle<Map> ComputeObjectLiteralMap(
271 Handle<Context> context,
272 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000273 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000274 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000275 int properties_length = constant_properties->length();
276 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000277 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000278 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000279 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000280 for (int p = 0; p != properties_length; p += 2) {
281 Object* key = constant_properties->get(p);
282 uint32_t element_index = 0;
283 if (key->IsSymbol()) {
284 number_of_symbol_keys++;
285 } else if (key->ToArrayIndex(&element_index)) {
286 // An index key does not require space in the property backing store.
287 number_of_properties--;
288 } else {
289 // Bail out as a non-symbol non-index key makes caching impossible.
290 // ASSERT to make sure that the if condition after the loop is false.
291 ASSERT(number_of_symbol_keys != number_of_properties);
292 break;
293 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000294 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000295 // If we only have symbols and array indices among keys then we can
296 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000297 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000298 if ((number_of_symbol_keys == number_of_properties) &&
299 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000300 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 Handle<FixedArray> keys =
302 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000303 if (number_of_symbol_keys > 0) {
304 int index = 0;
305 for (int p = 0; p < properties_length; p += 2) {
306 Object* key = constant_properties->get(p);
307 if (key->IsSymbol()) {
308 keys->set(index++, key);
309 }
310 }
311 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000312 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000313 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000314 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000315 }
316 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000317 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000319 Handle<Map>(context->object_function()->initial_map()),
320 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000321}
322
323
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000324static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000326 Handle<FixedArray> literals,
327 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000328
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000329
330static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000332 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000333 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000334 bool should_have_fast_elements,
335 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000336 // Get the global context from the literals array. This is the
337 // context in which the function was created and we use the object
338 // function from this context to create the object literal. We do
339 // not use the object function from the current global context
340 // because this might be the object function from another context
341 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000342 Handle<Context> context =
343 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 // In case we have function literals, we want the object to be in
346 // slow properties mode for now. We don't go in the map cache because
347 // maps with constant functions can't be shared if the functions are
348 // not the same (which is the common case).
349 bool is_result_from_cache = false;
350 Handle<Map> map = has_function_literal
351 ? Handle<Map>(context->object_function()->initial_map())
352 : ComputeObjectLiteralMap(context,
353 constant_properties,
354 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000356 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000357
358 // Normalize the elements of the boilerplate to save space if needed.
359 if (!should_have_fast_elements) NormalizeElements(boilerplate);
360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 // Add the constant properties to the boilerplate.
362 int length = constant_properties->length();
363 bool should_transform =
364 !is_result_from_cache && boilerplate->HasFastProperties();
365 if (should_transform || has_function_literal) {
366 // Normalize the properties of object to avoid n^2 behavior
367 // when extending the object multiple properties. Indicate the number of
368 // properties to be added.
369 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
370 }
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).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000387 result = SetOwnElement(boilerplate,
388 element_index,
389 value,
390 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000392 Handle<String> name(String::cast(*key));
393 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000394 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
395 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000396 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 } else if (key->ToArrayIndex(&element_index)) {
398 // Array index (uint32).
399 result = SetOwnElement(boilerplate,
400 element_index,
401 value,
402 kNonStrictMode);
403 } else {
404 // Non-uint32 number.
405 ASSERT(key->IsNumber());
406 double num = key->Number();
407 char arr[100];
408 Vector<char> buffer(arr, ARRAY_SIZE(arr));
409 const char* str = DoubleToCString(num, buffer);
410 Handle<String> name =
411 isolate->factory()->NewStringFromAscii(CStrVector(str));
412 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
413 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 // If setting the property on the boilerplate throws an
416 // exception, the exception is converted to an empty handle in
417 // the handle based operations. In that case, we need to
418 // convert back to an exception.
419 if (result.is_null()) return result;
420 }
421
422 // Transform to fast properties if necessary. For object literals with
423 // containing function literals we defer this operation until after all
424 // computed properties have been assigned so that we can generate
425 // constant function properties.
426 if (should_transform && !has_function_literal) {
427 TransformToFastProperties(boilerplate,
428 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000429 }
430
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000431 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000432}
433
434
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000435static const int kSmiOnlyLiteralMinimumLength = 1024;
436
437
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000438static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000440 Handle<FixedArray> literals,
441 Handle<FixedArray> elements) {
442 // Create the JSArray.
443 Handle<JSFunction> constructor(
444 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000445 Handle<JSArray> object =
446 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000447
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000448 ElementsKind constant_elements_kind =
449 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
450 Handle<FixedArrayBase> constant_elements_values(
451 FixedArrayBase::cast(elements->get(1)));
452
453 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
454 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
455 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
456 constant_elements_kind > object->GetElementsKind();
457
458 if (!FLAG_smi_only_arrays &&
459 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
460 constant_elements_kind != object->GetElementsKind()) {
461 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000462 }
463
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000464 // If the ElementsKind of the constant values of the array literal are less
465 // specific than the ElementsKind of the boilerplate array object, change the
466 // boilerplate array object's map to reflect that kind.
467 if (allow_literal_kind_transition) {
468 Handle<Map> transitioned_array_map =
469 isolate->factory()->GetElementsTransitionMap(object,
470 constant_elements_kind);
471 object->set_map(*transitioned_array_map);
472 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000473
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000474 Handle<FixedArrayBase> copied_elements_values;
475 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
476 ASSERT(FLAG_smi_only_arrays);
477 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
478 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000479 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000480 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
481 constant_elements_kind == FAST_ELEMENTS);
482 const bool is_cow =
483 (constant_elements_values->map() ==
484 isolate->heap()->fixed_cow_array_map());
485 if (is_cow) {
486 copied_elements_values = constant_elements_values;
487#if DEBUG
488 Handle<FixedArray> fixed_array_values =
489 Handle<FixedArray>::cast(copied_elements_values);
490 for (int i = 0; i < fixed_array_values->length(); i++) {
491 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
492 }
493#endif
494 } else {
495 Handle<FixedArray> fixed_array_values =
496 Handle<FixedArray>::cast(constant_elements_values);
497 Handle<FixedArray> fixed_array_values_copy =
498 isolate->factory()->CopyFixedArray(fixed_array_values);
499 copied_elements_values = fixed_array_values_copy;
500 for (int i = 0; i < fixed_array_values->length(); i++) {
501 Object* current = fixed_array_values->get(i);
502 if (current->IsFixedArray()) {
503 // The value contains the constant_properties of a
504 // simple object or array literal.
505 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
506 Handle<Object> result =
507 CreateLiteralBoilerplate(isolate, literals, fa);
508 if (result.is_null()) return result;
509 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000510 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000511 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 }
513 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000514 object->set_elements(*copied_elements_values);
515 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000516 return object;
517}
518
519
520static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522 Handle<FixedArray> literals,
523 Handle<FixedArray> array) {
524 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000526 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000528 return CreateObjectLiteralBoilerplate(isolate,
529 literals,
530 elements,
531 true,
532 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000533 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 return CreateObjectLiteralBoilerplate(isolate,
535 literals,
536 elements,
537 false,
538 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000541 default:
542 UNREACHABLE();
543 return Handle<Object>::null();
544 }
545}
546
547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000548RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000549 // Takes a FixedArray of elements containing the literal elements of
550 // the array literal and produces JSArray with those elements.
551 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000552 // which contains the context from which to get the Array function
553 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000555 ASSERT(args.length() == 3);
556 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000557 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000558 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 Handle<Object> object =
561 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000562 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000564 // Update the functions literal and return the boilerplate.
565 literals->set(literals_index, *object);
566 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000567}
568
569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000570RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000572 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000573 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000574 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000576 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
578 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579
580 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000581 Handle<Object> boilerplate(literals->get(literals_index), isolate);
582 if (*boilerplate == isolate->heap()->undefined_value()) {
583 boilerplate = CreateObjectLiteralBoilerplate(isolate,
584 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000585 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 should_have_fast_elements,
587 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000588 if (boilerplate.is_null()) return Failure::Exception();
589 // Update the functions literal and return the boilerplate.
590 literals->set(literals_index, *boilerplate);
591 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000592 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593}
594
595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000596RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000597 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000598 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000599 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000600 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000602 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
604 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000605
606 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000607 Handle<Object> boilerplate(literals->get(literals_index), isolate);
608 if (*boilerplate == isolate->heap()->undefined_value()) {
609 boilerplate = CreateObjectLiteralBoilerplate(isolate,
610 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000611 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000612 should_have_fast_elements,
613 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614 if (boilerplate.is_null()) return Failure::Exception();
615 // Update the functions literal and return the boilerplate.
616 literals->set(literals_index, *boilerplate);
617 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619}
620
621
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000622RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000623 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000624 ASSERT(args.length() == 3);
625 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000626 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000627 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
628
629 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000630 Handle<Object> boilerplate(literals->get(literals_index), isolate);
631 if (*boilerplate == isolate->heap()->undefined_value()) {
632 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000633 if (boilerplate.is_null()) return Failure::Exception();
634 // Update the functions literal and return the boilerplate.
635 literals->set(literals_index, *boilerplate);
636 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000637 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000638}
639
640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000641RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000642 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000643 ASSERT(args.length() == 3);
644 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000645 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000646 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
647
648 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000649 Handle<Object> boilerplate(literals->get(literals_index), isolate);
650 if (*boilerplate == isolate->heap()->undefined_value()) {
651 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000652 if (boilerplate.is_null()) return Failure::Exception();
653 // Update the functions literal and return the boilerplate.
654 literals->set(literals_index, *boilerplate);
655 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000656 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000658 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000659 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000661}
662
663
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
665 ASSERT(args.length() == 2);
666 Object* handler = args[0];
667 Object* prototype = args[1];
668 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000670 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
671}
672
673
lrn@chromium.org34e60782011-09-15 07:25:40 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
675 ASSERT(args.length() == 4);
676 Object* handler = args[0];
677 Object* call_trap = args[1];
678 Object* construct_trap = args[2];
679 Object* prototype = args[3];
680 Object* used_prototype =
681 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
682 return isolate->heap()->AllocateJSFunctionProxy(
683 handler, call_trap, construct_trap, used_prototype);
684}
685
686
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000687RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
688 ASSERT(args.length() == 1);
689 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000690 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000691}
692
693
lrn@chromium.org34e60782011-09-15 07:25:40 +0000694RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
695 ASSERT(args.length() == 1);
696 Object* obj = args[0];
697 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
698}
699
700
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000701RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
702 ASSERT(args.length() == 1);
703 CONVERT_CHECKED(JSProxy, proxy, args[0]);
704 return proxy->handler();
705}
706
707
lrn@chromium.org34e60782011-09-15 07:25:40 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
709 ASSERT(args.length() == 1);
710 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
711 return proxy->call_trap();
712}
713
714
715RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
716 ASSERT(args.length() == 1);
717 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
718 return proxy->construct_trap();
719}
720
721
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000722RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
723 ASSERT(args.length() == 1);
724 CONVERT_CHECKED(JSProxy, proxy, args[0]);
725 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000726 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000727}
728
729
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 1);
733 CONVERT_ARG_CHECKED(JSSet, holder, 0);
734 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
735 holder->set_table(*table);
736 return *holder;
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
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 = ObjectHashSetAdd(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 2);
755 CONVERT_ARG_CHECKED(JSSet, holder, 0);
756 Handle<Object> key(args[1]);
757 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
758 return isolate->heap()->ToBoolean(table->Contains(*key));
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
765 CONVERT_ARG_CHECKED(JSSet, holder, 0);
766 Handle<Object> key(args[1]);
767 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
768 table = ObjectHashSetRemove(table, key);
769 holder->set_table(*table);
770 return isolate->heap()->undefined_symbol();
771}
772
773
774RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
775 HandleScope scope(isolate);
776 ASSERT(args.length() == 1);
777 CONVERT_ARG_CHECKED(JSMap, holder, 0);
778 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
779 holder->set_table(*table);
780 return *holder;
781}
782
783
784RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 2);
787 CONVERT_ARG_CHECKED(JSMap, holder, 0);
788 Handle<Object> key(args[1]);
789 return ObjectHashTable::cast(holder->table())->Lookup(*key);
790}
791
792
793RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
794 HandleScope scope(isolate);
795 ASSERT(args.length() == 3);
796 CONVERT_ARG_CHECKED(JSMap, holder, 0);
797 Handle<Object> key(args[1]);
798 Handle<Object> value(args[2]);
799 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
800 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
801 holder->set_table(*new_table);
802 return *value;
803}
804
805
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000806RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
807 HandleScope scope(isolate);
808 ASSERT(args.length() == 1);
809 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
810 ASSERT(weakmap->map()->inobject_properties() == 0);
811 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
812 weakmap->set_table(*table);
813 weakmap->set_next(Smi::FromInt(0));
814 return *weakmap;
815}
816
817
818RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
819 NoHandleAllocation ha;
820 ASSERT(args.length() == 2);
821 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000822 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
823 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000824}
825
826
827RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
828 HandleScope scope(isolate);
829 ASSERT(args.length() == 3);
830 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000831 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000832 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000833 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000834 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
835 weakmap->set_table(*new_table);
836 return *value;
837}
838
839
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000840RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
843 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 return JSObject::cast(obj)->class_name();
846}
847
ager@chromium.org7c537e22008-10-16 08:43:32 +0000848
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
850 NoHandleAllocation ha;
851 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000852 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
853 Object* obj = input_obj;
854 // We don't expect access checks to be needed on JSProxy objects.
855 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000856 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000857 if (obj->IsAccessCheckNeeded() &&
858 !isolate->MayNamedAccess(JSObject::cast(obj),
859 isolate->heap()->Proto_symbol(),
860 v8::ACCESS_GET)) {
861 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
862 return isolate->heap()->undefined_value();
863 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000864 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000865 } while (obj->IsJSObject() &&
866 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000867 return obj;
868}
869
870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000871RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 NoHandleAllocation ha;
873 ASSERT(args.length() == 2);
874 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
875 Object* O = args[0];
876 Object* V = args[1];
877 while (true) {
878 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 if (prototype->IsNull()) return isolate->heap()->false_value();
880 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881 V = prototype;
882 }
883}
884
885
ager@chromium.org9085a012009-05-11 19:22:57 +0000886// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000887RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000888 NoHandleAllocation ha;
889 ASSERT(args.length() == 2);
890 CONVERT_CHECKED(JSObject, jsobject, args[0]);
891 CONVERT_CHECKED(JSObject, proto, args[1]);
892
893 // Sanity checks. The old prototype (that we are replacing) could
894 // theoretically be null, but if it is not null then check that we
895 // didn't already install a hidden prototype here.
896 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
897 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
898 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
899
900 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000901 Object* map_or_failure;
902 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
903 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
904 return maybe_map_or_failure;
905 }
906 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000907 Map* new_proto_map = Map::cast(map_or_failure);
908
lrn@chromium.org303ada72010-10-27 09:33:13 +0000909 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
910 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
911 return maybe_map_or_failure;
912 }
913 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000914 Map* new_map = Map::cast(map_or_failure);
915
916 // Set proto's prototype to be the old prototype of the object.
917 new_proto_map->set_prototype(jsobject->GetPrototype());
918 proto->set_map(new_proto_map);
919 new_proto_map->set_is_hidden_prototype();
920
921 // Set the object's prototype to proto.
922 new_map->set_prototype(proto);
923 jsobject->set_map(new_map);
924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000926}
927
928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000929RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000931 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000932 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000933 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934}
935
936
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000937// Recursively traverses hidden prototypes if property is not found
938static void GetOwnPropertyImplementation(JSObject* obj,
939 String* name,
940 LookupResult* result) {
941 obj->LocalLookupRealNamedProperty(name, result);
942
943 if (!result->IsProperty()) {
944 Object* proto = obj->GetPrototype();
945 if (proto->IsJSObject() &&
946 JSObject::cast(proto)->map()->is_hidden_prototype())
947 GetOwnPropertyImplementation(JSObject::cast(proto),
948 name, result);
949 }
950}
951
952
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000953static bool CheckAccessException(LookupResult* result,
954 v8::AccessType access_type) {
955 if (result->type() == CALLBACKS) {
956 Object* callback = result->GetCallbackObject();
957 if (callback->IsAccessorInfo()) {
958 AccessorInfo* info = AccessorInfo::cast(callback);
959 bool can_access =
960 (access_type == v8::ACCESS_HAS &&
961 (info->all_can_read() || info->all_can_write())) ||
962 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
963 (access_type == v8::ACCESS_SET && info->all_can_write());
964 return can_access;
965 }
966 }
967
968 return false;
969}
970
971
972static bool CheckAccess(JSObject* obj,
973 String* name,
974 LookupResult* result,
975 v8::AccessType access_type) {
976 ASSERT(result->IsProperty());
977
978 JSObject* holder = result->holder();
979 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000981 while (true) {
982 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000984 // Access check callback denied the access, but some properties
985 // can have a special permissions which override callbacks descision
986 // (currently see v8::AccessControl).
987 break;
988 }
989
990 if (current == holder) {
991 return true;
992 }
993
994 current = JSObject::cast(current->GetPrototype());
995 }
996
997 // API callbacks can have per callback access exceptions.
998 switch (result->type()) {
999 case CALLBACKS: {
1000 if (CheckAccessException(result, access_type)) {
1001 return true;
1002 }
1003 break;
1004 }
1005 case INTERCEPTOR: {
1006 // If the object has an interceptor, try real named properties.
1007 // Overwrite the result to fetch the correct property later.
1008 holder->LookupRealNamedProperty(name, result);
1009 if (result->IsProperty()) {
1010 if (CheckAccessException(result, access_type)) {
1011 return true;
1012 }
1013 }
1014 break;
1015 }
1016 default:
1017 break;
1018 }
1019
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001021 return false;
1022}
1023
1024
1025// TODO(1095): we should traverse hidden prototype hierachy as well.
1026static bool CheckElementAccess(JSObject* obj,
1027 uint32_t index,
1028 v8::AccessType access_type) {
1029 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001030 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001031 return false;
1032 }
1033
1034 return true;
1035}
1036
1037
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001038// Enumerator used as indices into the array returned from GetOwnProperty
1039enum PropertyDescriptorIndices {
1040 IS_ACCESSOR_INDEX,
1041 VALUE_INDEX,
1042 GETTER_INDEX,
1043 SETTER_INDEX,
1044 WRITABLE_INDEX,
1045 ENUMERABLE_INDEX,
1046 CONFIGURABLE_INDEX,
1047 DESCRIPTOR_SIZE
1048};
1049
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001050// Returns an array with the property description:
1051// if args[1] is not a property on args[0]
1052// returns undefined
1053// if args[1] is a data property on args[0]
1054// [false, value, Writeable, Enumerable, Configurable]
1055// if args[1] is an accessor on args[0]
1056// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001057RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001058 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001059 Heap* heap = isolate->heap();
1060 HandleScope scope(isolate);
1061 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1062 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001063 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001064 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1065 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001066
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001067 // This could be an element.
1068 uint32_t index;
1069 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001070 switch (obj->HasLocalElement(index)) {
1071 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001073
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001074 case JSObject::STRING_CHARACTER_ELEMENT: {
1075 // Special handling of string objects according to ECMAScript 5
1076 // 15.5.5.2. Note that this might be a string object with elements
1077 // other than the actual string value. This is covered by the
1078 // subsequent cases.
1079 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1080 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001081 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001082
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001085 elms->set(WRITABLE_INDEX, heap->false_value());
1086 elms->set(ENUMERABLE_INDEX, heap->false_value());
1087 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001088 return *desc;
1089 }
1090
1091 case JSObject::INTERCEPTED_ELEMENT:
1092 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001093 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001094 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001095 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001096 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097 elms->set(WRITABLE_INDEX, heap->true_value());
1098 elms->set(ENUMERABLE_INDEX, heap->true_value());
1099 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001100 return *desc;
1101 }
1102
1103 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001104 Handle<JSObject> holder = obj;
1105 if (obj->IsJSGlobalProxy()) {
1106 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001107 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001108 ASSERT(proto->IsJSGlobalObject());
1109 holder = Handle<JSObject>(JSObject::cast(proto));
1110 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001111 FixedArray* elements = FixedArray::cast(holder->elements());
1112 NumberDictionary* dictionary = NULL;
1113 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1114 dictionary = NumberDictionary::cast(elements->get(1));
1115 } else {
1116 dictionary = NumberDictionary::cast(elements);
1117 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001118 int entry = dictionary->FindEntry(index);
1119 ASSERT(entry != NumberDictionary::kNotFound);
1120 PropertyDetails details = dictionary->DetailsAt(entry);
1121 switch (details.type()) {
1122 case CALLBACKS: {
1123 // This is an accessor property with getter and/or setter.
1124 FixedArray* callbacks =
1125 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001126 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001127 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1128 elms->set(GETTER_INDEX, callbacks->get(0));
1129 }
1130 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1131 elms->set(SETTER_INDEX, callbacks->get(1));
1132 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001133 break;
1134 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001135 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001136 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001137 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001138 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001139 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001140 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001141 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001142 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001143 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001144 default:
1145 UNREACHABLE();
1146 break;
1147 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1149 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001150 return *desc;
1151 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001152 }
1153 }
1154
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001155 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001156 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001157
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001158 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001159 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001160 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001161
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001162 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001163 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001164 }
1165
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001166 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1167 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001168
1169 bool is_js_accessor = (result.type() == CALLBACKS) &&
1170 (result.GetCallbackObject()->IsFixedArray());
1171
1172 if (is_js_accessor) {
1173 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001174 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001175
1176 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1177 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1178 elms->set(GETTER_INDEX, structure->get(0));
1179 }
1180 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1181 elms->set(SETTER_INDEX, structure->get(1));
1182 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001183 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001184 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1185 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001186
1187 PropertyAttributes attrs;
1188 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001189 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001190 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1191 if (!maybe_value->ToObject(&value)) return maybe_value;
1192 }
1193 elms->set(VALUE_INDEX, value);
1194 }
1195
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001196 return *desc;
1197}
1198
1199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001200RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001201 ASSERT(args.length() == 1);
1202 CONVERT_CHECKED(JSObject, obj, args[0]);
1203 return obj->PreventExtensions();
1204}
1205
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001207RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001208 ASSERT(args.length() == 1);
1209 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001210 if (obj->IsJSGlobalProxy()) {
1211 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001212 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001213 ASSERT(proto->IsJSGlobalObject());
1214 obj = JSObject::cast(proto);
1215 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001216 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001217}
1218
1219
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001220RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001221 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001223 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1224 CONVERT_ARG_CHECKED(String, pattern, 1);
1225 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001226 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1227 if (result.is_null()) return Failure::Exception();
1228 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229}
1230
1231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001232RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001233 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001235 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001236 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237}
1238
1239
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001240RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 ASSERT(args.length() == 1);
1242 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001243 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001244 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245}
1246
1247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001248RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 ASSERT(args.length() == 2);
1250 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001252 int index = field->value();
1253 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1254 InstanceType type = templ->map()->instance_type();
1255 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1256 type == OBJECT_TEMPLATE_INFO_TYPE);
1257 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001258 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001259 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1260 } else {
1261 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1262 }
1263 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001264}
1265
1266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001267RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001268 ASSERT(args.length() == 1);
1269 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001270 Map* old_map = object->map();
1271 bool needs_access_checks = old_map->is_access_check_needed();
1272 if (needs_access_checks) {
1273 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001274 Object* new_map;
1275 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1276 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1277 }
ager@chromium.org32912102009-01-16 10:38:43 +00001278
1279 Map::cast(new_map)->set_is_access_check_needed(false);
1280 object->set_map(Map::cast(new_map));
1281 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001282 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001283}
1284
1285
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001286RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001287 ASSERT(args.length() == 1);
1288 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001289 Map* old_map = object->map();
1290 if (!old_map->is_access_check_needed()) {
1291 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001292 Object* new_map;
1293 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1294 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1295 }
ager@chromium.org32912102009-01-16 10:38:43 +00001296
1297 Map::cast(new_map)->set_is_access_check_needed(true);
1298 object->set_map(Map::cast(new_map));
1299 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001300 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001301}
1302
1303
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001304static Failure* ThrowRedeclarationError(Isolate* isolate,
1305 const char* type,
1306 Handle<String> name) {
1307 HandleScope scope(isolate);
1308 Handle<Object> type_handle =
1309 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 Handle<Object> args[2] = { type_handle, name };
1311 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001312 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1313 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314}
1315
1316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001317RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001318 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001319 HandleScope scope(isolate);
1320 Handle<GlobalObject> global = Handle<GlobalObject>(
1321 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001322
ager@chromium.org3811b432009-10-28 14:53:37 +00001323 Handle<Context> context = args.at<Context>(0);
1324 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001325 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 // Traverse the name/value pairs and set the properties.
1328 int length = pairs->length();
1329 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001330 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001332 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001333
1334 // We have to declare a global const property. To capture we only
1335 // assign to it when evaluating the assignment for "const x =
1336 // <expr>" the initial value is the hole.
1337 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001338 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339 if (value->IsUndefined() || is_const_property) {
1340 // Lookup the property in the global object, and don't set the
1341 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001342 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343 global->Lookup(*name, &lookup);
1344 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001345 // We found an existing property. Unless it was an interceptor
1346 // that claims the property is absent, skip this declaration.
1347 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348 continue;
1349 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001350 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1351 if (attributes != ABSENT) {
1352 continue;
1353 }
1354 // Fall-through and introduce the absent property by using
1355 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 }
1357 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001358 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001359 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001360 Handle<SharedFunctionInfo> shared =
1361 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001362 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001363 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1364 context,
1365 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366 value = function;
1367 }
1368
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001369 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 global->LocalLookup(*name, &lookup);
1371
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001372 // Compute the property attributes. According to ECMA-262, section
1373 // 13, page 71, the property must be read-only and
1374 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1375 // property as read-only, so we don't either.
1376 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001377 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001378 attr |= DONT_DELETE;
1379 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001380 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001381 if (is_const_property || (is_native && is_function_declaration)) {
1382 attr |= READ_ONLY;
1383 }
1384
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001385 // Safari does not allow the invocation of callback setters for
1386 // function declarations. To mimic this behavior, we do not allow
1387 // the invocation of setters for function values. This makes a
1388 // difference for global functions with the same names as event
1389 // handlers such as "function onload() {}". Firefox does call the
1390 // onload setter in those case and Safari does not. We follow
1391 // Safari for compatibility.
1392 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001393 // Do not change DONT_DELETE to false from true.
1394 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001395 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001396 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001397 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1398
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001399 RETURN_IF_EMPTY_HANDLE(isolate,
1400 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001401 name,
1402 value,
1403 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001405 StrictModeFlag strict_mode = DeclareGlobalsStrictModeFlag::decode(flags);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001406 RETURN_IF_EMPTY_HANDLE(isolate,
1407 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001408 name,
1409 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001410 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001411 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412 }
1413 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001415 ASSERT(!isolate->has_pending_exception());
1416 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417}
1418
1419
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001420RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001422 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 // Declarations are always made in a function or global context. In the
1425 // case of eval code, the context passed is the context of the caller,
1426 // which may be some nested context and not the declaration context.
1427 RUNTIME_ASSERT(args[0]->IsContext());
1428 Handle<Context> context(Context::cast(args[0])->declaration_context());
1429
ager@chromium.org7c537e22008-10-16 08:43:32 +00001430 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001431 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001432 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001433 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435 int index;
1436 PropertyAttributes attributes;
1437 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001438 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001439 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001440 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001441
1442 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001443 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1445 // Functions are not read-only.
1446 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1447 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001448 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449 }
1450
1451 // Initialize it if necessary.
1452 if (*initial_value != NULL) {
1453 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001454 ASSERT(holder.is_identical_to(context));
1455 if (((attributes & READ_ONLY) == 0) ||
1456 context->get(index)->IsTheHole()) {
1457 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001458 }
1459 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001460 // Slow case: The property is in the context extension object of a
1461 // function context or the global object of a global context.
1462 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001463 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001465 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466 }
1467 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001470 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001471 // "declared" in the function context's extension context or as a
1472 // property of the the global object.
1473 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001474 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001475 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001476 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001477 // Context extension objects are allocated lazily.
1478 ASSERT(context->IsFunctionContext());
1479 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001480 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001481 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001482 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001483 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484
ager@chromium.org7c537e22008-10-16 08:43:32 +00001485 // Declare the property by setting it to the initial value if provided,
1486 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1487 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001488 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001489 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001490 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001491 // Declaring a const context slot is a conflicting declaration if
1492 // there is a callback with that name in a prototype. It is
1493 // allowed to introduce const variables in
1494 // JSContextExtensionObjects. They are treated specially in
1495 // SetProperty and no setters are invoked for those since they are
1496 // not real JSObjects.
1497 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001498 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001499 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001500 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001501 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001502 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001503 }
1504 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001505 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001507 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001508 }
1509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001510 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001511}
1512
1513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001514RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001516 // args[0] == name
1517 // args[1] == strict_mode
1518 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519
1520 // Determine if we need to assign to the variable if it already
1521 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001522 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1523 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524
1525 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001526 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001527 RUNTIME_ASSERT(args[1]->IsSmi());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00001528 CONVERT_STRICT_MODE_ARG(strict_mode, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529
1530 // According to ECMA-262, section 12.2, page 62, the property must
1531 // not be deletable.
1532 PropertyAttributes attributes = DONT_DELETE;
1533
1534 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001535 // there, there is a property with this name in the prototype chain.
1536 // We follow Safari and Firefox behavior and only set the property
1537 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001538 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001539 // Note that objects can have hidden prototypes, so we need to traverse
1540 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001541 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001542 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001543 while (object->IsJSObject() &&
1544 JSObject::cast(object)->map()->is_hidden_prototype()) {
1545 JSObject* raw_holder = JSObject::cast(object);
1546 raw_holder->LocalLookup(*name, &lookup);
1547 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1548 HandleScope handle_scope(isolate);
1549 Handle<JSObject> holder(raw_holder);
1550 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1551 // Update the raw pointer in case it's changed due to GC.
1552 raw_holder = *holder;
1553 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1554 // Found an interceptor that's not read only.
1555 if (assign) {
1556 return raw_holder->SetProperty(
1557 &lookup, *name, args[2], attributes, strict_mode);
1558 } else {
1559 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001560 }
1561 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001562 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001563 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 }
1565
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001566 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001567 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001568 if (assign) {
1569 return global->SetProperty(*name, args[2], attributes, strict_mode);
1570 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572}
1573
1574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001575RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 // All constants are declared with an initial value. The name
1577 // of the constant is the first argument and the initial value
1578 // is the second.
1579 RUNTIME_ASSERT(args.length() == 2);
1580 CONVERT_ARG_CHECKED(String, name, 0);
1581 Handle<Object> value = args.at<Object>(1);
1582
1583 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001584 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585
1586 // According to ECMA-262, section 12.2, page 62, the property must
1587 // not be deletable. Since it's a const, it must be READ_ONLY too.
1588 PropertyAttributes attributes =
1589 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1590
1591 // Lookup the property locally in the global object. If it isn't
1592 // there, we add the property and take special precautions to always
1593 // add it as a local property even in case of callbacks in the
1594 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001595 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001596 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001597 global->LocalLookup(*name, &lookup);
1598 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001599 return global->SetLocalPropertyIgnoreAttributes(*name,
1600 *value,
1601 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 }
1603
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001606 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001607 HandleScope handle_scope(isolate);
1608 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001609
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001610 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611 // property through an interceptor and only do it if it's
1612 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001613 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001614 RETURN_IF_EMPTY_HANDLE(isolate,
1615 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001616 name,
1617 value,
1618 attributes,
1619 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 return *value;
1621 }
1622
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001623 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001624 // constant. For now, we determine this by checking if the
1625 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001626 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 PropertyType type = lookup.type();
1628 if (type == FIELD) {
1629 FixedArray* properties = global->properties();
1630 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001631 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632 properties->set(index, *value);
1633 }
1634 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001635 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1636 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001637 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638 }
1639 } else {
1640 // Ignore re-initialization of constants that have already been
1641 // assigned a function value.
1642 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1643 }
1644
1645 // Use the set value as the result of the operation.
1646 return *value;
1647}
1648
1649
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001650RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001651 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001652 ASSERT(args.length() == 3);
1653
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001654 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001655 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001656
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001657 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001658 RUNTIME_ASSERT(args[1]->IsContext());
1659 Handle<Context> context(Context::cast(args[1])->declaration_context());
1660
1661 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001662
1663 int index;
1664 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001665 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001666 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001667 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001668 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001670 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001671 ASSERT(holder->IsContext());
1672 // Property was found in a context. Perform the assignment if we
1673 // found some non-constant or an uninitialized constant.
1674 Handle<Context> context = Handle<Context>::cast(holder);
1675 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1676 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001677 }
1678 return *value;
1679 }
1680
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001681 // The property could not be found, we introduce it as a property of the
1682 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001683 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001684 Handle<JSObject> global = Handle<JSObject>(
1685 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001686 // Strict mode not needed (const disallowed in strict mode).
1687 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001689 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001690 return *value;
1691 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001693 // The property was present in some function's context extension object,
1694 // as a property on the subject of a with, or as a property of the global
1695 // object.
1696 //
1697 // In most situations, eval-introduced consts should still be present in
1698 // the context extension object. However, because declaration and
1699 // initialization are separate, the property might have been deleted
1700 // before we reach the initialization point.
1701 //
1702 // Example:
1703 //
1704 // function f() { eval("delete x; const x;"); }
1705 //
1706 // In that case, the initialization behaves like a normal assignment.
1707 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001708
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001709 if (*object == context->extension()) {
1710 // This is the property that was introduced by the const declaration.
1711 // Set it if it hasn't been set before. NOTE: We cannot use
1712 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001713 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001714 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001715 ASSERT(lookup.IsProperty()); // the property was declared
1716 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1717
1718 PropertyType type = lookup.type();
1719 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001720 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001721 int index = lookup.GetFieldIndex();
1722 if (properties->get(index)->IsTheHole()) {
1723 properties->set(index, *value);
1724 }
1725 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001726 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1727 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001728 }
1729 } else {
1730 // We should not reach here. Any real, named property should be
1731 // either a field or a dictionary slot.
1732 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001733 }
1734 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001735 // The property was found on some other object. Set it if it is not a
1736 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001737 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001738 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001739 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001741 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001742 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001744
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001745 return *value;
1746}
1747
1748
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001749RUNTIME_FUNCTION(MaybeObject*,
1750 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001751 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001752 ASSERT(args.length() == 2);
1753 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001754 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001755 if (object->HasFastProperties()) {
1756 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1757 }
1758 return *object;
1759}
1760
1761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001762RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001764 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001765 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1766 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001767 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001768 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001769 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001770 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001771 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001772 RUNTIME_ASSERT(index >= 0);
1773 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001774 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001775 Handle<Object> result = RegExpImpl::Exec(regexp,
1776 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001777 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001778 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001779 if (result.is_null()) return Failure::Exception();
1780 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001781}
1782
1783
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001784RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001785 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001786 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001787 if (elements_count < 0 ||
1788 elements_count > FixedArray::kMaxLength ||
1789 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001790 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001791 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001792 Object* new_object;
1793 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001794 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001795 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1796 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001797 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1799 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001800 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1801 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001802 {
1803 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001805 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001806 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001807 }
1808 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001810 array->set_elements(elements);
1811 array->set_length(Smi::FromInt(elements_count));
1812 // Write in-object properties after the length of the array.
1813 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1814 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1815 return array;
1816}
1817
1818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001819RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001820 AssertNoAllocation no_alloc;
1821 ASSERT(args.length() == 5);
1822 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1823 CONVERT_CHECKED(String, source, args[1]);
1824
1825 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001827
1828 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001829 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001830
1831 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001833
1834 Map* map = regexp->map();
1835 Object* constructor = map->constructor();
1836 if (constructor->IsJSFunction() &&
1837 JSFunction::cast(constructor)->initial_map() == map) {
1838 // If we still have the original map, set in-object properties directly.
1839 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1840 // TODO(lrn): Consider skipping write barrier on booleans as well.
1841 // Both true and false should be in oldspace at all times.
1842 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1843 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1844 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1845 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1846 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001847 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001848 return regexp;
1849 }
1850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001851 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001852 PropertyAttributes final =
1853 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1854 PropertyAttributes writable =
1855 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001856 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001857 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001858 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001859 source,
1860 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001861 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001862 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001863 global,
1864 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001865 ASSERT(!result->IsFailure());
1866 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001867 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001868 ignoreCase,
1869 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001870 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001871 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001872 multiline,
1873 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001874 ASSERT(!result->IsFailure());
1875 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001876 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001877 Smi::FromInt(0),
1878 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001879 ASSERT(!result->IsFailure());
1880 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001881 return regexp;
1882}
1883
1884
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001885RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001886 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001887 ASSERT(args.length() == 1);
1888 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1889 // This is necessary to enable fast checks for absence of elements
1890 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001891 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001892 return Smi::FromInt(0);
1893}
1894
1895
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001896static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1897 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001898 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001899 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001900 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1901 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1902 Handle<JSFunction> optimized =
1903 isolate->factory()->NewFunction(key,
1904 JS_OBJECT_TYPE,
1905 JSObject::kHeaderSize,
1906 code,
1907 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001908 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001909 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001910 return optimized;
1911}
1912
1913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001914RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001915 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001916 ASSERT(args.length() == 1);
1917 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1918
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001919 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1920 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1921 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1922 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1923 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1924 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1925 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001926
1927 return *holder;
1928}
1929
1930
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001931RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1932 NoHandleAllocation handle_free;
1933 ASSERT(args.length() == 1);
1934 CONVERT_CHECKED(JSFunction, function, args[0]);
1935 SharedFunctionInfo* shared = function->shared();
1936 if (shared->native() || shared->strict_mode()) {
1937 return isolate->heap()->undefined_value();
1938 }
1939 // Returns undefined for strict or native functions, or
1940 // the associated global receiver for "normal" functions.
1941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001942 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001943 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001944 return global_context->global()->global_receiver();
1945}
1946
1947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001949 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001950 ASSERT(args.length() == 4);
1951 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001952 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 Handle<String> pattern = args.at<String>(2);
1954 Handle<String> flags = args.at<String>(3);
1955
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001956 // Get the RegExp function from the context in the literals array.
1957 // This is the RegExp function from the context in which the
1958 // function was created. We do not use the RegExp function from the
1959 // current global context because this might be the RegExp function
1960 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001961 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001962 Handle<JSFunction>(
1963 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001964 // Compute the regular expression literal.
1965 bool has_pending_exception;
1966 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001967 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1968 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001969 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001970 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001971 return Failure::Exception();
1972 }
1973 literals->set(index, *regexp);
1974 return *regexp;
1975}
1976
1977
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001978RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001979 NoHandleAllocation ha;
1980 ASSERT(args.length() == 1);
1981
1982 CONVERT_CHECKED(JSFunction, f, args[0]);
1983 return f->shared()->name();
1984}
1985
1986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001987RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001988 NoHandleAllocation ha;
1989 ASSERT(args.length() == 2);
1990
1991 CONVERT_CHECKED(JSFunction, f, args[0]);
1992 CONVERT_CHECKED(String, name, args[1]);
1993 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001994 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001995}
1996
1997
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1999 NoHandleAllocation ha;
2000 ASSERT(args.length() == 1);
2001 CONVERT_CHECKED(JSFunction, f, args[0]);
2002 return isolate->heap()->ToBoolean(
2003 f->shared()->name_should_print_as_anonymous());
2004}
2005
2006
2007RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
2008 NoHandleAllocation ha;
2009 ASSERT(args.length() == 1);
2010 CONVERT_CHECKED(JSFunction, f, args[0]);
2011 f->shared()->set_name_should_print_as_anonymous(true);
2012 return isolate->heap()->undefined_value();
2013}
2014
2015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002016RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002017 NoHandleAllocation ha;
2018 ASSERT(args.length() == 1);
2019
2020 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002021 Object* obj = f->RemovePrototype();
2022 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002023
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002024 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002025}
2026
2027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002028RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002029 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002030 ASSERT(args.length() == 1);
2031
2032 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002033 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
2034 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002035
2036 return *GetScriptWrapper(Handle<Script>::cast(script));
2037}
2038
2039
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002040RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002041 NoHandleAllocation ha;
2042 ASSERT(args.length() == 1);
2043
2044 CONVERT_CHECKED(JSFunction, f, args[0]);
2045 return f->shared()->GetSourceCode();
2046}
2047
2048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002049RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002050 NoHandleAllocation ha;
2051 ASSERT(args.length() == 1);
2052
2053 CONVERT_CHECKED(JSFunction, fun, args[0]);
2054 int pos = fun->shared()->start_position();
2055 return Smi::FromInt(pos);
2056}
2057
2058
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002059RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002060 ASSERT(args.length() == 2);
2061
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002062 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002063 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2064
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002065 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2066
2067 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002068 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002069}
2070
2071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002072RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073 NoHandleAllocation ha;
2074 ASSERT(args.length() == 2);
2075
2076 CONVERT_CHECKED(JSFunction, fun, args[0]);
2077 CONVERT_CHECKED(String, name, args[1]);
2078 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002079 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002080}
2081
2082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002083RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002084 NoHandleAllocation ha;
2085 ASSERT(args.length() == 2);
2086
2087 CONVERT_CHECKED(JSFunction, fun, args[0]);
2088 CONVERT_CHECKED(Smi, length, args[1]);
2089 fun->shared()->set_length(length->value());
2090 return length;
2091}
2092
2093
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002094RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002095 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002096 ASSERT(args.length() == 2);
2097
2098 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002099 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002100 Object* obj;
2101 { MaybeObject* maybe_obj =
2102 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2103 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2104 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002105 return args[0]; // return TOS
2106}
2107
2108
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002109RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2110 NoHandleAllocation ha;
2111 RUNTIME_ASSERT(args.length() == 1);
2112 CONVERT_CHECKED(JSFunction, function, args[0]);
2113
2114 MaybeObject* maybe_name =
2115 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2116 String* name;
2117 if (!maybe_name->To(&name)) return maybe_name;
2118
2119 if (function->HasFastProperties()) {
2120 // Construct a new field descriptor with updated attributes.
2121 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2122 int index = instance_desc->Search(name);
2123 ASSERT(index != DescriptorArray::kNotFound);
2124 PropertyDetails details(instance_desc->GetDetails(index));
2125 CallbacksDescriptor new_desc(name,
2126 instance_desc->GetValue(index),
2127 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2128 details.index());
2129 // Construct a new field descriptors array containing the new descriptor.
2130 Object* descriptors_unchecked;
2131 { MaybeObject* maybe_descriptors_unchecked =
2132 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2133 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2134 return maybe_descriptors_unchecked;
2135 }
2136 }
2137 DescriptorArray* new_descriptors =
2138 DescriptorArray::cast(descriptors_unchecked);
2139 // Create a new map featuring the new field descriptors array.
2140 Object* map_unchecked;
2141 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2142 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2143 return maybe_map_unchecked;
2144 }
2145 }
2146 Map* new_map = Map::cast(map_unchecked);
2147 new_map->set_instance_descriptors(new_descriptors);
2148 function->set_map(new_map);
2149 } else { // Dictionary properties.
2150 // Directly manipulate the property details.
2151 int entry = function->property_dictionary()->FindEntry(name);
2152 ASSERT(entry != StringDictionary::kNotFound);
2153 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2154 PropertyDetails new_details(
2155 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2156 details.type(),
2157 details.index());
2158 function->property_dictionary()->DetailsAtPut(entry, new_details);
2159 }
2160 return function;
2161}
2162
2163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002164RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002165 NoHandleAllocation ha;
2166 ASSERT(args.length() == 1);
2167
2168 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002169 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002170}
2171
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002173RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002174 NoHandleAllocation ha;
2175 ASSERT(args.length() == 1);
2176
2177 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002178 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002179}
2180
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002182RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002183 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002184 ASSERT(args.length() == 2);
2185
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002186 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002187 Handle<Object> code = args.at<Object>(1);
2188
2189 Handle<Context> context(target->context());
2190
2191 if (!code->IsNull()) {
2192 RUNTIME_ASSERT(code->IsJSFunction());
2193 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002194 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002195
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002196 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002197 return Failure::Exception();
2198 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002199 // Since we don't store the source for this we should never
2200 // optimize this.
2201 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002202 // Set the code, scope info, formal parameter count,
2203 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002204 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002205 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002206 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002207 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002208 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002209 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002210 // Set the source code of the target function to undefined.
2211 // SetCode is only used for built-in constructors like String,
2212 // Array, and Object, and some web code
2213 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002215 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002216 // Clear the optimization hints related to the compiled code as these are no
2217 // longer valid when the code is overwritten.
2218 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002219 context = Handle<Context>(fun->context());
2220
2221 // Make sure we get a fresh copy of the literal vector to avoid
2222 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002223 int number_of_literals = fun->NumberOfLiterals();
2224 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002225 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002226 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002227 // Insert the object, regexp and array functions in the literals
2228 // array prefix. These are the functions that will be used when
2229 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002230 literals->set(JSFunction::kLiteralGlobalContextIndex,
2231 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002232 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002233 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002234 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002235
2236 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2237 isolate->logger()->LogExistingFunction(
2238 shared, Handle<Code>(shared->code()));
2239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002240 }
2241
2242 target->set_context(*context);
2243 return *target;
2244}
2245
2246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002247RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002248 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002249 ASSERT(args.length() == 2);
2250 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002251 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002252 RUNTIME_ASSERT(num >= 0);
2253 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002255}
2256
2257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002258MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2259 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002260 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002261 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002262 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002263 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002264 }
2265 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002266 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002267}
2268
2269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002270RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002271 NoHandleAllocation ha;
2272 ASSERT(args.length() == 2);
2273
2274 CONVERT_CHECKED(String, subject, args[0]);
2275 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002276 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002277
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002278 uint32_t i = 0;
2279 if (index->IsSmi()) {
2280 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002281 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002282 i = value;
2283 } else {
2284 ASSERT(index->IsHeapNumber());
2285 double value = HeapNumber::cast(index)->value();
2286 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002287 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002288
2289 // Flatten the string. If someone wants to get a char at an index
2290 // in a cons string, it is likely that more indices will be
2291 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002292 Object* flat;
2293 { MaybeObject* maybe_flat = subject->TryFlatten();
2294 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2295 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002296 subject = String::cast(flat);
2297
2298 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002299 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002300 }
2301
2302 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002303}
2304
2305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002306RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002307 NoHandleAllocation ha;
2308 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002309 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002310}
2311
lrn@chromium.org25156de2010-04-06 13:10:27 +00002312
2313class FixedArrayBuilder {
2314 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002315 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2316 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002317 length_(0),
2318 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002319 // Require a non-zero initial size. Ensures that doubling the size to
2320 // extend the array will work.
2321 ASSERT(initial_capacity > 0);
2322 }
2323
2324 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2325 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002326 length_(0),
2327 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002328 // Require a non-zero initial size. Ensures that doubling the size to
2329 // extend the array will work.
2330 ASSERT(backing_store->length() > 0);
2331 }
2332
2333 bool HasCapacity(int elements) {
2334 int length = array_->length();
2335 int required_length = length_ + elements;
2336 return (length >= required_length);
2337 }
2338
2339 void EnsureCapacity(int elements) {
2340 int length = array_->length();
2341 int required_length = length_ + elements;
2342 if (length < required_length) {
2343 int new_length = length;
2344 do {
2345 new_length *= 2;
2346 } while (new_length < required_length);
2347 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002348 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002349 array_->CopyTo(0, *extended_array, 0, length_);
2350 array_ = extended_array;
2351 }
2352 }
2353
2354 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002355 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002356 ASSERT(length_ < capacity());
2357 array_->set(length_, value);
2358 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002359 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002360 }
2361
2362 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002363 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002364 ASSERT(length_ < capacity());
2365 array_->set(length_, value);
2366 length_++;
2367 }
2368
2369 Handle<FixedArray> array() {
2370 return array_;
2371 }
2372
2373 int length() {
2374 return length_;
2375 }
2376
2377 int capacity() {
2378 return array_->length();
2379 }
2380
2381 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002382 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002383 result_array->set_length(Smi::FromInt(length_));
2384 return result_array;
2385 }
2386
2387 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002388 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002389 target_array->set_length(Smi::FromInt(length_));
2390 return target_array;
2391 }
2392
2393 private:
2394 Handle<FixedArray> array_;
2395 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002396 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002397};
2398
2399
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002400// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002401const int kStringBuilderConcatHelperLengthBits = 11;
2402const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002403
2404template <typename schar>
2405static inline void StringBuilderConcatHelper(String*,
2406 schar*,
2407 FixedArray*,
2408 int);
2409
lrn@chromium.org25156de2010-04-06 13:10:27 +00002410typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2411 StringBuilderSubstringLength;
2412typedef BitField<int,
2413 kStringBuilderConcatHelperLengthBits,
2414 kStringBuilderConcatHelperPositionBits>
2415 StringBuilderSubstringPosition;
2416
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002417
2418class ReplacementStringBuilder {
2419 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002420 ReplacementStringBuilder(Heap* heap,
2421 Handle<String> subject,
2422 int estimated_part_count)
2423 : heap_(heap),
2424 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002425 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002426 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002427 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 // Require a non-zero initial size. Ensures that doubling the size to
2429 // extend the array will work.
2430 ASSERT(estimated_part_count > 0);
2431 }
2432
lrn@chromium.org25156de2010-04-06 13:10:27 +00002433 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2434 int from,
2435 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002436 ASSERT(from >= 0);
2437 int length = to - from;
2438 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 if (StringBuilderSubstringLength::is_valid(length) &&
2440 StringBuilderSubstringPosition::is_valid(from)) {
2441 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2442 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002443 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002445 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002446 builder->Add(Smi::FromInt(-length));
2447 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002449 }
2450
2451
2452 void EnsureCapacity(int elements) {
2453 array_builder_.EnsureCapacity(elements);
2454 }
2455
2456
2457 void AddSubjectSlice(int from, int to) {
2458 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002459 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002460 }
2461
2462
2463 void AddString(Handle<String> string) {
2464 int length = string->length();
2465 ASSERT(length > 0);
2466 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002467 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 is_ascii_ = false;
2469 }
2470 IncrementCharacterCount(length);
2471 }
2472
2473
2474 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002475 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002476 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002477 }
2478
2479 Handle<String> joined_string;
2480 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002481 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002482 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002483 char* char_buffer = seq->GetChars();
2484 StringBuilderConcatHelper(*subject_,
2485 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002486 *array_builder_.array(),
2487 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002488 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002489 } else {
2490 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002491 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002492 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002493 uc16* char_buffer = seq->GetChars();
2494 StringBuilderConcatHelper(*subject_,
2495 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002496 *array_builder_.array(),
2497 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002498 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002499 }
2500 return joined_string;
2501 }
2502
2503
2504 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002505 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002506 V8::FatalProcessOutOfMemory("String.replace result too large.");
2507 }
2508 character_count_ += by;
2509 }
2510
lrn@chromium.org25156de2010-04-06 13:10:27 +00002511 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002512 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002513 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002514
lrn@chromium.org25156de2010-04-06 13:10:27 +00002515 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002516 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2517 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002518 }
2519
2520
ager@chromium.org04921a82011-06-27 13:21:41 +00002521 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2522 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002523 }
2524
2525
2526 void AddElement(Object* element) {
2527 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002528 ASSERT(array_builder_.capacity() > array_builder_.length());
2529 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002530 }
2531
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002532 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002533 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002534 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002535 int character_count_;
2536 bool is_ascii_;
2537};
2538
2539
2540class CompiledReplacement {
2541 public:
2542 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002543 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002544
2545 void Compile(Handle<String> replacement,
2546 int capture_count,
2547 int subject_length);
2548
2549 void Apply(ReplacementStringBuilder* builder,
2550 int match_from,
2551 int match_to,
2552 Handle<JSArray> last_match_info);
2553
2554 // Number of distinct parts of the replacement pattern.
2555 int parts() {
2556 return parts_.length();
2557 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002558
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002559 bool simple_hint() {
2560 return simple_hint_;
2561 }
2562
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002563 private:
2564 enum PartType {
2565 SUBJECT_PREFIX = 1,
2566 SUBJECT_SUFFIX,
2567 SUBJECT_CAPTURE,
2568 REPLACEMENT_SUBSTRING,
2569 REPLACEMENT_STRING,
2570
2571 NUMBER_OF_PART_TYPES
2572 };
2573
2574 struct ReplacementPart {
2575 static inline ReplacementPart SubjectMatch() {
2576 return ReplacementPart(SUBJECT_CAPTURE, 0);
2577 }
2578 static inline ReplacementPart SubjectCapture(int capture_index) {
2579 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2580 }
2581 static inline ReplacementPart SubjectPrefix() {
2582 return ReplacementPart(SUBJECT_PREFIX, 0);
2583 }
2584 static inline ReplacementPart SubjectSuffix(int subject_length) {
2585 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2586 }
2587 static inline ReplacementPart ReplacementString() {
2588 return ReplacementPart(REPLACEMENT_STRING, 0);
2589 }
2590 static inline ReplacementPart ReplacementSubString(int from, int to) {
2591 ASSERT(from >= 0);
2592 ASSERT(to > from);
2593 return ReplacementPart(-from, to);
2594 }
2595
2596 // If tag <= 0 then it is the negation of a start index of a substring of
2597 // the replacement pattern, otherwise it's a value from PartType.
2598 ReplacementPart(int tag, int data)
2599 : tag(tag), data(data) {
2600 // Must be non-positive or a PartType value.
2601 ASSERT(tag < NUMBER_OF_PART_TYPES);
2602 }
2603 // Either a value of PartType or a non-positive number that is
2604 // the negation of an index into the replacement string.
2605 int tag;
2606 // The data value's interpretation depends on the value of tag:
2607 // tag == SUBJECT_PREFIX ||
2608 // tag == SUBJECT_SUFFIX: data is unused.
2609 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2610 // tag == REPLACEMENT_SUBSTRING ||
2611 // tag == REPLACEMENT_STRING: data is index into array of substrings
2612 // of the replacement string.
2613 // tag <= 0: Temporary representation of the substring of the replacement
2614 // string ranging over -tag .. data.
2615 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2616 // substring objects.
2617 int data;
2618 };
2619
2620 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002621 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002622 Vector<Char> characters,
2623 int capture_count,
2624 int subject_length) {
2625 int length = characters.length();
2626 int last = 0;
2627 for (int i = 0; i < length; i++) {
2628 Char c = characters[i];
2629 if (c == '$') {
2630 int next_index = i + 1;
2631 if (next_index == length) { // No next character!
2632 break;
2633 }
2634 Char c2 = characters[next_index];
2635 switch (c2) {
2636 case '$':
2637 if (i > last) {
2638 // There is a substring before. Include the first "$".
2639 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2640 last = next_index + 1; // Continue after the second "$".
2641 } else {
2642 // Let the next substring start with the second "$".
2643 last = next_index;
2644 }
2645 i = next_index;
2646 break;
2647 case '`':
2648 if (i > last) {
2649 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2650 }
2651 parts->Add(ReplacementPart::SubjectPrefix());
2652 i = next_index;
2653 last = i + 1;
2654 break;
2655 case '\'':
2656 if (i > last) {
2657 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2658 }
2659 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2660 i = next_index;
2661 last = i + 1;
2662 break;
2663 case '&':
2664 if (i > last) {
2665 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2666 }
2667 parts->Add(ReplacementPart::SubjectMatch());
2668 i = next_index;
2669 last = i + 1;
2670 break;
2671 case '0':
2672 case '1':
2673 case '2':
2674 case '3':
2675 case '4':
2676 case '5':
2677 case '6':
2678 case '7':
2679 case '8':
2680 case '9': {
2681 int capture_ref = c2 - '0';
2682 if (capture_ref > capture_count) {
2683 i = next_index;
2684 continue;
2685 }
2686 int second_digit_index = next_index + 1;
2687 if (second_digit_index < length) {
2688 // Peek ahead to see if we have two digits.
2689 Char c3 = characters[second_digit_index];
2690 if ('0' <= c3 && c3 <= '9') { // Double digits.
2691 int double_digit_ref = capture_ref * 10 + c3 - '0';
2692 if (double_digit_ref <= capture_count) {
2693 next_index = second_digit_index;
2694 capture_ref = double_digit_ref;
2695 }
2696 }
2697 }
2698 if (capture_ref > 0) {
2699 if (i > last) {
2700 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2701 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002702 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002703 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2704 last = next_index + 1;
2705 }
2706 i = next_index;
2707 break;
2708 }
2709 default:
2710 i = next_index;
2711 break;
2712 }
2713 }
2714 }
2715 if (length > last) {
2716 if (last == 0) {
2717 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002718 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002719 } else {
2720 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2721 }
2722 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002723 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002724 }
2725
2726 ZoneList<ReplacementPart> parts_;
2727 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002728 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002729};
2730
2731
2732void CompiledReplacement::Compile(Handle<String> replacement,
2733 int capture_count,
2734 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002735 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002736 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002737 String::FlatContent content = replacement->GetFlatContent();
2738 ASSERT(content.IsFlat());
2739 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002740 simple_hint_ = ParseReplacementPattern(&parts_,
2741 content.ToAsciiVector(),
2742 capture_count,
2743 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002744 } else {
2745 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002746 simple_hint_ = ParseReplacementPattern(&parts_,
2747 content.ToUC16Vector(),
2748 capture_count,
2749 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002750 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002751 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002752 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002753 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002754 int substring_index = 0;
2755 for (int i = 0, n = parts_.length(); i < n; i++) {
2756 int tag = parts_[i].tag;
2757 if (tag <= 0) { // A replacement string slice.
2758 int from = -tag;
2759 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002760 replacement_substrings_.Add(
2761 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002762 parts_[i].tag = REPLACEMENT_SUBSTRING;
2763 parts_[i].data = substring_index;
2764 substring_index++;
2765 } else if (tag == REPLACEMENT_STRING) {
2766 replacement_substrings_.Add(replacement);
2767 parts_[i].data = substring_index;
2768 substring_index++;
2769 }
2770 }
2771}
2772
2773
2774void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2775 int match_from,
2776 int match_to,
2777 Handle<JSArray> last_match_info) {
2778 for (int i = 0, n = parts_.length(); i < n; i++) {
2779 ReplacementPart part = parts_[i];
2780 switch (part.tag) {
2781 case SUBJECT_PREFIX:
2782 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2783 break;
2784 case SUBJECT_SUFFIX: {
2785 int subject_length = part.data;
2786 if (match_to < subject_length) {
2787 builder->AddSubjectSlice(match_to, subject_length);
2788 }
2789 break;
2790 }
2791 case SUBJECT_CAPTURE: {
2792 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002793 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002794 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2795 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2796 if (from >= 0 && to > from) {
2797 builder->AddSubjectSlice(from, to);
2798 }
2799 break;
2800 }
2801 case REPLACEMENT_SUBSTRING:
2802 case REPLACEMENT_STRING:
2803 builder->AddString(replacement_substrings_[part.data]);
2804 break;
2805 default:
2806 UNREACHABLE();
2807 }
2808 }
2809}
2810
2811
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002812void FindAsciiStringIndices(Vector<const char> subject,
2813 char pattern,
2814 ZoneList<int>* indices,
2815 unsigned int limit) {
2816 ASSERT(limit > 0);
2817 // Collect indices of pattern in subject using memchr.
2818 // Stop after finding at most limit values.
2819 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2820 const char* subject_end = subject_start + subject.length();
2821 const char* pos = subject_start;
2822 while (limit > 0) {
2823 pos = reinterpret_cast<const char*>(
2824 memchr(pos, pattern, subject_end - pos));
2825 if (pos == NULL) return;
2826 indices->Add(static_cast<int>(pos - subject_start));
2827 pos++;
2828 limit--;
2829 }
2830}
2831
2832
2833template <typename SubjectChar, typename PatternChar>
2834void FindStringIndices(Isolate* isolate,
2835 Vector<const SubjectChar> subject,
2836 Vector<const PatternChar> pattern,
2837 ZoneList<int>* indices,
2838 unsigned int limit) {
2839 ASSERT(limit > 0);
2840 // Collect indices of pattern in subject.
2841 // Stop after finding at most limit values.
2842 int pattern_length = pattern.length();
2843 int index = 0;
2844 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2845 while (limit > 0) {
2846 index = search.Search(subject, index);
2847 if (index < 0) return;
2848 indices->Add(index);
2849 index += pattern_length;
2850 limit--;
2851 }
2852}
2853
2854
2855void FindStringIndicesDispatch(Isolate* isolate,
2856 String* subject,
2857 String* pattern,
2858 ZoneList<int>* indices,
2859 unsigned int limit) {
2860 {
2861 AssertNoAllocation no_gc;
2862 String::FlatContent subject_content = subject->GetFlatContent();
2863 String::FlatContent pattern_content = pattern->GetFlatContent();
2864 ASSERT(subject_content.IsFlat());
2865 ASSERT(pattern_content.IsFlat());
2866 if (subject_content.IsAscii()) {
2867 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2868 if (pattern_content.IsAscii()) {
2869 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2870 if (pattern_vector.length() == 1) {
2871 FindAsciiStringIndices(subject_vector,
2872 pattern_vector[0],
2873 indices,
2874 limit);
2875 } else {
2876 FindStringIndices(isolate,
2877 subject_vector,
2878 pattern_vector,
2879 indices,
2880 limit);
2881 }
2882 } else {
2883 FindStringIndices(isolate,
2884 subject_vector,
2885 pattern_content.ToUC16Vector(),
2886 indices,
2887 limit);
2888 }
2889 } else {
2890 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002891 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002892 FindStringIndices(isolate,
2893 subject_vector,
2894 pattern_content.ToAsciiVector(),
2895 indices,
2896 limit);
2897 } else {
2898 FindStringIndices(isolate,
2899 subject_vector,
2900 pattern_content.ToUC16Vector(),
2901 indices,
2902 limit);
2903 }
2904 }
2905 }
2906}
2907
2908
2909template<typename ResultSeqString>
2910MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2911 Isolate* isolate,
2912 Handle<String> subject,
2913 Handle<JSRegExp> pattern_regexp,
2914 Handle<String> replacement) {
2915 ASSERT(subject->IsFlat());
2916 ASSERT(replacement->IsFlat());
2917
2918 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2919 ZoneList<int> indices(8);
2920 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2921 String* pattern =
2922 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2923 int subject_len = subject->length();
2924 int pattern_len = pattern->length();
2925 int replacement_len = replacement->length();
2926
2927 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2928
2929 int matches = indices.length();
2930 if (matches == 0) return *subject;
2931
2932 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2933 int subject_pos = 0;
2934 int result_pos = 0;
2935
2936 Handle<ResultSeqString> result;
2937 if (ResultSeqString::kHasAsciiEncoding) {
2938 result = Handle<ResultSeqString>::cast(
2939 isolate->factory()->NewRawAsciiString(result_len));
2940 } else {
2941 result = Handle<ResultSeqString>::cast(
2942 isolate->factory()->NewRawTwoByteString(result_len));
2943 }
2944
2945 for (int i = 0; i < matches; i++) {
2946 // Copy non-matched subject content.
2947 if (subject_pos < indices.at(i)) {
2948 String::WriteToFlat(*subject,
2949 result->GetChars() + result_pos,
2950 subject_pos,
2951 indices.at(i));
2952 result_pos += indices.at(i) - subject_pos;
2953 }
2954
2955 // Replace match.
2956 if (replacement_len > 0) {
2957 String::WriteToFlat(*replacement,
2958 result->GetChars() + result_pos,
2959 0,
2960 replacement_len);
2961 result_pos += replacement_len;
2962 }
2963
2964 subject_pos = indices.at(i) + pattern_len;
2965 }
2966 // Add remaining subject content at the end.
2967 if (subject_pos < subject_len) {
2968 String::WriteToFlat(*subject,
2969 result->GetChars() + result_pos,
2970 subject_pos,
2971 subject_len);
2972 }
2973 return *result;
2974}
2975
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002976
lrn@chromium.org303ada72010-10-27 09:33:13 +00002977MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002978 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002979 String* subject,
2980 JSRegExp* regexp,
2981 String* replacement,
2982 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002983 ASSERT(subject->IsFlat());
2984 ASSERT(replacement->IsFlat());
2985
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002986 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002987
2988 int length = subject->length();
2989 Handle<String> subject_handle(subject);
2990 Handle<JSRegExp> regexp_handle(regexp);
2991 Handle<String> replacement_handle(replacement);
2992 Handle<JSArray> last_match_info_handle(last_match_info);
2993 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2994 subject_handle,
2995 0,
2996 last_match_info_handle);
2997 if (match.is_null()) {
2998 return Failure::Exception();
2999 }
3000 if (match->IsNull()) {
3001 return *subject_handle;
3002 }
3003
3004 int capture_count = regexp_handle->CaptureCount();
3005
3006 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003007 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003008 CompiledReplacement compiled_replacement;
3009 compiled_replacement.Compile(replacement_handle,
3010 capture_count,
3011 length);
3012
3013 bool is_global = regexp_handle->GetFlags().is_global();
3014
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003015 // Shortcut for simple non-regexp global replacements
3016 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003017 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003018 compiled_replacement.simple_hint()) {
3019 if (subject_handle->HasOnlyAsciiChars() &&
3020 replacement_handle->HasOnlyAsciiChars()) {
3021 return StringReplaceStringWithString<SeqAsciiString>(
3022 isolate, subject_handle, regexp_handle, replacement_handle);
3023 } else {
3024 return StringReplaceStringWithString<SeqTwoByteString>(
3025 isolate, subject_handle, regexp_handle, replacement_handle);
3026 }
3027 }
3028
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003029 // Guessing the number of parts that the final result string is built
3030 // from. Global regexps can match any number of times, so we guess
3031 // conservatively.
3032 int expected_parts =
3033 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003034 ReplacementStringBuilder builder(isolate->heap(),
3035 subject_handle,
3036 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003037
3038 // Index of end of last match.
3039 int prev = 0;
3040
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003041 // Number of parts added by compiled replacement plus preceeding
3042 // string and possibly suffix after last match. It is possible for
3043 // all components to use two elements when encoded as two smis.
3044 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003045 bool matched = true;
3046 do {
3047 ASSERT(last_match_info_handle->HasFastElements());
3048 // Increase the capacity of the builder before entering local handle-scope,
3049 // so its internal buffer can safely allocate a new handle if it grows.
3050 builder.EnsureCapacity(parts_added_per_loop);
3051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003052 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003053 int start, end;
3054 {
3055 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003056 FixedArray* match_info_array =
3057 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003058
3059 ASSERT_EQ(capture_count * 2 + 2,
3060 RegExpImpl::GetLastCaptureCount(match_info_array));
3061 start = RegExpImpl::GetCapture(match_info_array, 0);
3062 end = RegExpImpl::GetCapture(match_info_array, 1);
3063 }
3064
3065 if (prev < start) {
3066 builder.AddSubjectSlice(prev, start);
3067 }
3068 compiled_replacement.Apply(&builder,
3069 start,
3070 end,
3071 last_match_info_handle);
3072 prev = end;
3073
3074 // Only continue checking for global regexps.
3075 if (!is_global) break;
3076
3077 // Continue from where the match ended, unless it was an empty match.
3078 int next = end;
3079 if (start == end) {
3080 next = end + 1;
3081 if (next > length) break;
3082 }
3083
3084 match = RegExpImpl::Exec(regexp_handle,
3085 subject_handle,
3086 next,
3087 last_match_info_handle);
3088 if (match.is_null()) {
3089 return Failure::Exception();
3090 }
3091 matched = !match->IsNull();
3092 } while (matched);
3093
3094 if (prev < length) {
3095 builder.AddSubjectSlice(prev, length);
3096 }
3097
3098 return *(builder.ToString());
3099}
3100
3101
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003102template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003103MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003104 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003105 String* subject,
3106 JSRegExp* regexp,
3107 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003108 ASSERT(subject->IsFlat());
3109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003110 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003111
3112 Handle<String> subject_handle(subject);
3113 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003114
3115 // Shortcut for simple non-regexp global replacements
3116 if (regexp_handle->GetFlags().is_global() &&
3117 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3118 Handle<String> empty_string_handle(HEAP->empty_string());
3119 if (subject_handle->HasOnlyAsciiChars()) {
3120 return StringReplaceStringWithString<SeqAsciiString>(
3121 isolate, subject_handle, regexp_handle, empty_string_handle);
3122 } else {
3123 return StringReplaceStringWithString<SeqTwoByteString>(
3124 isolate, subject_handle, regexp_handle, empty_string_handle);
3125 }
3126 }
3127
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003128 Handle<JSArray> last_match_info_handle(last_match_info);
3129 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3130 subject_handle,
3131 0,
3132 last_match_info_handle);
3133 if (match.is_null()) return Failure::Exception();
3134 if (match->IsNull()) return *subject_handle;
3135
3136 ASSERT(last_match_info_handle->HasFastElements());
3137
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003138 int start, end;
3139 {
3140 AssertNoAllocation match_info_array_is_not_in_a_handle;
3141 FixedArray* match_info_array =
3142 FixedArray::cast(last_match_info_handle->elements());
3143
3144 start = RegExpImpl::GetCapture(match_info_array, 0);
3145 end = RegExpImpl::GetCapture(match_info_array, 1);
3146 }
3147
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003148 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003149 int new_length = length - (end - start);
3150 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003151 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003152 }
3153 Handle<ResultSeqString> answer;
3154 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003155 answer = Handle<ResultSeqString>::cast(
3156 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003157 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003158 answer = Handle<ResultSeqString>::cast(
3159 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003160 }
3161
3162 // If the regexp isn't global, only match once.
3163 if (!regexp_handle->GetFlags().is_global()) {
3164 if (start > 0) {
3165 String::WriteToFlat(*subject_handle,
3166 answer->GetChars(),
3167 0,
3168 start);
3169 }
3170 if (end < length) {
3171 String::WriteToFlat(*subject_handle,
3172 answer->GetChars() + start,
3173 end,
3174 length);
3175 }
3176 return *answer;
3177 }
3178
3179 int prev = 0; // Index of end of last match.
3180 int next = 0; // Start of next search (prev unless last match was empty).
3181 int position = 0;
3182
3183 do {
3184 if (prev < start) {
3185 // Add substring subject[prev;start] to answer string.
3186 String::WriteToFlat(*subject_handle,
3187 answer->GetChars() + position,
3188 prev,
3189 start);
3190 position += start - prev;
3191 }
3192 prev = end;
3193 next = end;
3194 // Continue from where the match ended, unless it was an empty match.
3195 if (start == end) {
3196 next++;
3197 if (next > length) break;
3198 }
3199 match = RegExpImpl::Exec(regexp_handle,
3200 subject_handle,
3201 next,
3202 last_match_info_handle);
3203 if (match.is_null()) return Failure::Exception();
3204 if (match->IsNull()) break;
3205
3206 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003207 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003208 {
3209 AssertNoAllocation match_info_array_is_not_in_a_handle;
3210 FixedArray* match_info_array =
3211 FixedArray::cast(last_match_info_handle->elements());
3212 start = RegExpImpl::GetCapture(match_info_array, 0);
3213 end = RegExpImpl::GetCapture(match_info_array, 1);
3214 }
3215 } while (true);
3216
3217 if (prev < length) {
3218 // Add substring subject[prev;length] to answer string.
3219 String::WriteToFlat(*subject_handle,
3220 answer->GetChars() + position,
3221 prev,
3222 length);
3223 position += length - prev;
3224 }
3225
3226 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003227 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003228 }
3229
3230 // Shorten string and fill
3231 int string_size = ResultSeqString::SizeFor(position);
3232 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3233 int delta = allocated_string_size - string_size;
3234
3235 answer->set_length(position);
3236 if (delta == 0) return *answer;
3237
3238 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003240 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3241 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3242 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003243
3244 return *answer;
3245}
3246
3247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003248RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003249 ASSERT(args.length() == 4);
3250
3251 CONVERT_CHECKED(String, subject, args[0]);
3252 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003253 Object* flat_subject;
3254 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3255 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3256 return maybe_flat_subject;
3257 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003258 }
3259 subject = String::cast(flat_subject);
3260 }
3261
3262 CONVERT_CHECKED(String, replacement, args[2]);
3263 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003264 Object* flat_replacement;
3265 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3266 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3267 return maybe_flat_replacement;
3268 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003269 }
3270 replacement = String::cast(flat_replacement);
3271 }
3272
3273 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3274 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3275
3276 ASSERT(last_match_info->HasFastElements());
3277
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003278 if (replacement->length() == 0) {
3279 if (subject->HasOnlyAsciiChars()) {
3280 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003281 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003282 } else {
3283 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003284 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003285 }
3286 }
3287
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003288 return StringReplaceRegExpWithString(isolate,
3289 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003290 regexp,
3291 replacement,
3292 last_match_info);
3293}
3294
3295
ager@chromium.org7c537e22008-10-16 08:43:32 +00003296// Perform string match of pattern on subject, starting at start index.
3297// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003298// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003299int Runtime::StringMatch(Isolate* isolate,
3300 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003301 Handle<String> pat,
3302 int start_index) {
3303 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003304 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003305
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003306 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003307 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003308
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003309 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003310 if (start_index + pattern_length > subject_length) return -1;
3311
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003312 if (!sub->IsFlat()) FlattenString(sub);
3313 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003314
ager@chromium.org7c537e22008-10-16 08:43:32 +00003315 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003316 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003317 String::FlatContent seq_sub = sub->GetFlatContent();
3318 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003319
ager@chromium.org7c537e22008-10-16 08:43:32 +00003320 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003321 if (seq_pat.IsAscii()) {
3322 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3323 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003324 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003325 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003326 pat_vector,
3327 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003328 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003329 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003330 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003331 pat_vector,
3332 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003333 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003334 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3335 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003336 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003337 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003338 pat_vector,
3339 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003340 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003341 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003342 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003343 pat_vector,
3344 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003345}
3346
3347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003348RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003349 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003350 ASSERT(args.length() == 3);
3351
ager@chromium.org7c537e22008-10-16 08:43:32 +00003352 CONVERT_ARG_CHECKED(String, sub, 0);
3353 CONVERT_ARG_CHECKED(String, pat, 1);
3354
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003355 Object* index = args[2];
3356 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003357 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003358
ager@chromium.org870a0b62008-11-04 11:43:05 +00003359 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003360 int position =
3361 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003362 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363}
3364
3365
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003366template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003367static int StringMatchBackwards(Vector<const schar> subject,
3368 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003369 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003370 int pattern_length = pattern.length();
3371 ASSERT(pattern_length >= 1);
3372 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003373
3374 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003375 for (int i = 0; i < pattern_length; i++) {
3376 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003377 if (c > String::kMaxAsciiCharCode) {
3378 return -1;
3379 }
3380 }
3381 }
3382
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003383 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003384 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003385 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003386 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003387 while (j < pattern_length) {
3388 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003389 break;
3390 }
3391 j++;
3392 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003393 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003394 return i;
3395 }
3396 }
3397 return -1;
3398}
3399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003400RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003401 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003402 ASSERT(args.length() == 3);
3403
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003404 CONVERT_ARG_CHECKED(String, sub, 0);
3405 CONVERT_ARG_CHECKED(String, pat, 1);
3406
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003408 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003409 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003411 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003412 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003413
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003414 if (start_index + pat_length > sub_length) {
3415 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003416 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003417
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003418 if (pat_length == 0) {
3419 return Smi::FromInt(start_index);
3420 }
3421
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003422 if (!sub->IsFlat()) FlattenString(sub);
3423 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003424
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003425 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003426 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3427
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003428 String::FlatContent sub_content = sub->GetFlatContent();
3429 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003430
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003431 if (pat_content.IsAscii()) {
3432 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3433 if (sub_content.IsAscii()) {
3434 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003435 pat_vector,
3436 start_index);
3437 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003438 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003439 pat_vector,
3440 start_index);
3441 }
3442 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003443 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3444 if (sub_content.IsAscii()) {
3445 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003446 pat_vector,
3447 start_index);
3448 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003449 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003450 pat_vector,
3451 start_index);
3452 }
3453 }
3454
3455 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003456}
3457
3458
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003459RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003460 NoHandleAllocation ha;
3461 ASSERT(args.length() == 2);
3462
3463 CONVERT_CHECKED(String, str1, args[0]);
3464 CONVERT_CHECKED(String, str2, args[1]);
3465
3466 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003467 int str1_length = str1->length();
3468 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003469
3470 // Decide trivial cases without flattening.
3471 if (str1_length == 0) {
3472 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3473 return Smi::FromInt(-str2_length);
3474 } else {
3475 if (str2_length == 0) return Smi::FromInt(str1_length);
3476 }
3477
3478 int end = str1_length < str2_length ? str1_length : str2_length;
3479
3480 // No need to flatten if we are going to find the answer on the first
3481 // character. At this point we know there is at least one character
3482 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003483 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003484 if (d != 0) return Smi::FromInt(d);
3485
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003486 str1->TryFlatten();
3487 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003489 StringInputBuffer& buf1 =
3490 *isolate->runtime_state()->string_locale_compare_buf1();
3491 StringInputBuffer& buf2 =
3492 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003493
3494 buf1.Reset(str1);
3495 buf2.Reset(str2);
3496
3497 for (int i = 0; i < end; i++) {
3498 uint16_t char1 = buf1.GetNext();
3499 uint16_t char2 = buf2.GetNext();
3500 if (char1 != char2) return Smi::FromInt(char1 - char2);
3501 }
3502
3503 return Smi::FromInt(str1_length - str2_length);
3504}
3505
3506
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003507RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003508 NoHandleAllocation ha;
3509 ASSERT(args.length() == 3);
3510
3511 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003512 int start, end;
3513 // We have a fast integer-only case here to avoid a conversion to double in
3514 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003515 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3516 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3517 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3518 start = from_number;
3519 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003520 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003521 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3522 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003523 start = FastD2I(from_number);
3524 end = FastD2I(to_number);
3525 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003526 RUNTIME_ASSERT(end >= start);
3527 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003528 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003529 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003530 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003531}
3532
3533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003534RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003535 ASSERT_EQ(3, args.length());
3536
3537 CONVERT_ARG_CHECKED(String, subject, 0);
3538 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3539 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3540 HandleScope handles;
3541
3542 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3543
3544 if (match.is_null()) {
3545 return Failure::Exception();
3546 }
3547 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003548 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003549 }
3550 int length = subject->length();
3551
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003552 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003553 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003554 int start;
3555 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003556 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003557 {
3558 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003559 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003560 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3561 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3562 }
3563 offsets.Add(start);
3564 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003565 if (start == end) if (++end > length) break;
3566 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003567 if (match.is_null()) {
3568 return Failure::Exception();
3569 }
3570 } while (!match->IsNull());
3571 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003572 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003573 Handle<String> substring = isolate->factory()->
3574 NewSubString(subject, offsets.at(0), offsets.at(1));
3575 elements->set(0, *substring);
3576 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003577 int from = offsets.at(i * 2);
3578 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003579 Handle<String> substring = isolate->factory()->
3580 NewProperSubString(subject, from, to);
3581 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003582 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003583 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003584 result->set_length(Smi::FromInt(matches));
3585 return *result;
3586}
3587
3588
lrn@chromium.org25156de2010-04-06 13:10:27 +00003589// Two smis before and after the match, for very long strings.
3590const int kMaxBuilderEntriesPerRegExpMatch = 5;
3591
3592
3593static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3594 Handle<JSArray> last_match_info,
3595 int match_start,
3596 int match_end) {
3597 // Fill last_match_info with a single capture.
3598 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3599 AssertNoAllocation no_gc;
3600 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3601 RegExpImpl::SetLastCaptureCount(elements, 2);
3602 RegExpImpl::SetLastInput(elements, *subject);
3603 RegExpImpl::SetLastSubject(elements, *subject);
3604 RegExpImpl::SetCapture(elements, 0, match_start);
3605 RegExpImpl::SetCapture(elements, 1, match_end);
3606}
3607
3608
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003609template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003610static bool SearchStringMultiple(Isolate* isolate,
3611 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003612 Vector<const PatternChar> pattern,
3613 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003614 FixedArrayBuilder* builder,
3615 int* match_pos) {
3616 int pos = *match_pos;
3617 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003618 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003619 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003620 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003621 while (pos <= max_search_start) {
3622 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3623 *match_pos = pos;
3624 return false;
3625 }
3626 // Position of end of previous match.
3627 int match_end = pos + pattern_length;
3628 int new_pos = search.Search(subject, match_end);
3629 if (new_pos >= 0) {
3630 // A match.
3631 if (new_pos > match_end) {
3632 ReplacementStringBuilder::AddSubjectSlice(builder,
3633 match_end,
3634 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003635 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003636 pos = new_pos;
3637 builder->Add(pattern_string);
3638 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003639 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003640 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003641 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003642
lrn@chromium.org25156de2010-04-06 13:10:27 +00003643 if (pos < max_search_start) {
3644 ReplacementStringBuilder::AddSubjectSlice(builder,
3645 pos + pattern_length,
3646 subject_length);
3647 }
3648 *match_pos = pos;
3649 return true;
3650}
3651
3652
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003653static bool SearchStringMultiple(Isolate* isolate,
3654 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003655 Handle<String> pattern,
3656 Handle<JSArray> last_match_info,
3657 FixedArrayBuilder* builder) {
3658 ASSERT(subject->IsFlat());
3659 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003660
3661 // Treating as if a previous match was before first character.
3662 int match_pos = -pattern->length();
3663
3664 for (;;) { // Break when search complete.
3665 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3666 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003667 String::FlatContent subject_content = subject->GetFlatContent();
3668 String::FlatContent pattern_content = pattern->GetFlatContent();
3669 if (subject_content.IsAscii()) {
3670 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3671 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003672 if (SearchStringMultiple(isolate,
3673 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003674 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003675 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003676 builder,
3677 &match_pos)) break;
3678 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003679 if (SearchStringMultiple(isolate,
3680 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003681 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003682 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003683 builder,
3684 &match_pos)) break;
3685 }
3686 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003687 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3688 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003689 if (SearchStringMultiple(isolate,
3690 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003691 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003692 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003693 builder,
3694 &match_pos)) break;
3695 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003696 if (SearchStringMultiple(isolate,
3697 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003698 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003699 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003700 builder,
3701 &match_pos)) break;
3702 }
3703 }
3704 }
3705
3706 if (match_pos >= 0) {
3707 SetLastMatchInfoNoCaptures(subject,
3708 last_match_info,
3709 match_pos,
3710 match_pos + pattern->length());
3711 return true;
3712 }
3713 return false; // No matches at all.
3714}
3715
3716
3717static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003718 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003719 Handle<String> subject,
3720 Handle<JSRegExp> regexp,
3721 Handle<JSArray> last_match_array,
3722 FixedArrayBuilder* builder) {
3723 ASSERT(subject->IsFlat());
3724 int match_start = -1;
3725 int match_end = 0;
3726 int pos = 0;
3727 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3728 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3729
3730 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003731 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003732 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003733 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003734
3735 for (;;) { // Break on failure, return on exception.
3736 RegExpImpl::IrregexpResult result =
3737 RegExpImpl::IrregexpExecOnce(regexp,
3738 subject,
3739 pos,
3740 register_vector);
3741 if (result == RegExpImpl::RE_SUCCESS) {
3742 match_start = register_vector[0];
3743 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3744 if (match_end < match_start) {
3745 ReplacementStringBuilder::AddSubjectSlice(builder,
3746 match_end,
3747 match_start);
3748 }
3749 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003750 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003751 if (!first) {
3752 builder->Add(*isolate->factory()->NewProperSubString(subject,
3753 match_start,
3754 match_end));
3755 } else {
3756 builder->Add(*isolate->factory()->NewSubString(subject,
3757 match_start,
3758 match_end));
3759 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003760 if (match_start != match_end) {
3761 pos = match_end;
3762 } else {
3763 pos = match_end + 1;
3764 if (pos > subject_length) break;
3765 }
3766 } else if (result == RegExpImpl::RE_FAILURE) {
3767 break;
3768 } else {
3769 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3770 return result;
3771 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003772 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003773 }
3774
3775 if (match_start >= 0) {
3776 if (match_end < subject_length) {
3777 ReplacementStringBuilder::AddSubjectSlice(builder,
3778 match_end,
3779 subject_length);
3780 }
3781 SetLastMatchInfoNoCaptures(subject,
3782 last_match_array,
3783 match_start,
3784 match_end);
3785 return RegExpImpl::RE_SUCCESS;
3786 } else {
3787 return RegExpImpl::RE_FAILURE; // No matches at all.
3788 }
3789}
3790
3791
3792static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003793 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003794 Handle<String> subject,
3795 Handle<JSRegExp> regexp,
3796 Handle<JSArray> last_match_array,
3797 FixedArrayBuilder* builder) {
3798
3799 ASSERT(subject->IsFlat());
3800 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3801 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3802
3803 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003804 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003805
3806 RegExpImpl::IrregexpResult result =
3807 RegExpImpl::IrregexpExecOnce(regexp,
3808 subject,
3809 0,
3810 register_vector);
3811
3812 int capture_count = regexp->CaptureCount();
3813 int subject_length = subject->length();
3814
3815 // Position to search from.
3816 int pos = 0;
3817 // End of previous match. Differs from pos if match was empty.
3818 int match_end = 0;
3819 if (result == RegExpImpl::RE_SUCCESS) {
3820 // Need to keep a copy of the previous match for creating last_match_info
3821 // at the end, so we have two vectors that we swap between.
3822 OffsetsVector registers2(required_registers);
3823 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003824 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003825 do {
3826 int match_start = register_vector[0];
3827 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3828 if (match_end < match_start) {
3829 ReplacementStringBuilder::AddSubjectSlice(builder,
3830 match_end,
3831 match_start);
3832 }
3833 match_end = register_vector[1];
3834
3835 {
3836 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003837 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003838 // Arguments array to replace function is match, captures, index and
3839 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003840 Handle<FixedArray> elements =
3841 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003842 Handle<String> match;
3843 if (!first) {
3844 match = isolate->factory()->NewProperSubString(subject,
3845 match_start,
3846 match_end);
3847 } else {
3848 match = isolate->factory()->NewSubString(subject,
3849 match_start,
3850 match_end);
3851 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003852 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003853 for (int i = 1; i <= capture_count; i++) {
3854 int start = register_vector[i * 2];
3855 if (start >= 0) {
3856 int end = register_vector[i * 2 + 1];
3857 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003858 Handle<String> substring;
3859 if (!first) {
3860 substring = isolate->factory()->NewProperSubString(subject,
3861 start,
3862 end);
3863 } else {
3864 substring = isolate->factory()->NewSubString(subject, start, end);
3865 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003866 elements->set(i, *substring);
3867 } else {
3868 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003869 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003870 }
3871 }
3872 elements->set(capture_count + 1, Smi::FromInt(match_start));
3873 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003874 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003875 }
3876 // Swap register vectors, so the last successful match is in
3877 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003878 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003879 prev_register_vector = register_vector;
3880 register_vector = tmp;
3881
3882 if (match_end > match_start) {
3883 pos = match_end;
3884 } else {
3885 pos = match_end + 1;
3886 if (pos > subject_length) {
3887 break;
3888 }
3889 }
3890
3891 result = RegExpImpl::IrregexpExecOnce(regexp,
3892 subject,
3893 pos,
3894 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003895 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003896 } while (result == RegExpImpl::RE_SUCCESS);
3897
3898 if (result != RegExpImpl::RE_EXCEPTION) {
3899 // Finished matching, with at least one match.
3900 if (match_end < subject_length) {
3901 ReplacementStringBuilder::AddSubjectSlice(builder,
3902 match_end,
3903 subject_length);
3904 }
3905
3906 int last_match_capture_count = (capture_count + 1) * 2;
3907 int last_match_array_size =
3908 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3909 last_match_array->EnsureSize(last_match_array_size);
3910 AssertNoAllocation no_gc;
3911 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3912 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3913 RegExpImpl::SetLastSubject(elements, *subject);
3914 RegExpImpl::SetLastInput(elements, *subject);
3915 for (int i = 0; i < last_match_capture_count; i++) {
3916 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3917 }
3918 return RegExpImpl::RE_SUCCESS;
3919 }
3920 }
3921 // No matches at all, return failure or exception result directly.
3922 return result;
3923}
3924
3925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003926RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003927 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003928 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003929
3930 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003931 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003932 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3933 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3934 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3935
3936 ASSERT(last_match_info->HasFastElements());
3937 ASSERT(regexp->GetFlags().is_global());
3938 Handle<FixedArray> result_elements;
3939 if (result_array->HasFastElements()) {
3940 result_elements =
3941 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003942 }
3943 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003944 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003945 }
3946 FixedArrayBuilder builder(result_elements);
3947
3948 if (regexp->TypeTag() == JSRegExp::ATOM) {
3949 Handle<String> pattern(
3950 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003951 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003952 if (SearchStringMultiple(isolate, subject, pattern,
3953 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003954 return *builder.ToJSArray(result_array);
3955 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003956 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003957 }
3958
3959 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3960
3961 RegExpImpl::IrregexpResult result;
3962 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003963 result = SearchRegExpNoCaptureMultiple(isolate,
3964 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003965 regexp,
3966 last_match_info,
3967 &builder);
3968 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003969 result = SearchRegExpMultiple(isolate,
3970 subject,
3971 regexp,
3972 last_match_info,
3973 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003974 }
3975 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003976 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003977 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3978 return Failure::Exception();
3979}
3980
3981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003982RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983 NoHandleAllocation ha;
3984 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003985 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003986 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003987
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003988 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003989 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003990 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003991 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003992 // Character array used for conversion.
3993 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003994 return isolate->heap()->
3995 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003996 }
3997 }
3998
3999 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004000 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004001 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004002 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003 }
4004 if (isinf(value)) {
4005 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004006 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004007 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004008 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004011 MaybeObject* result =
4012 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004013 DeleteArray(str);
4014 return result;
4015}
4016
4017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004018RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 NoHandleAllocation ha;
4020 ASSERT(args.length() == 2);
4021
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004022 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004023 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004024 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004025 }
4026 if (isinf(value)) {
4027 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004028 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004029 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004030 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004031 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004032 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 int f = FastD2I(f_number);
4034 RUNTIME_ASSERT(f >= 0);
4035 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004036 MaybeObject* res =
4037 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004039 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040}
4041
4042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004043RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004044 NoHandleAllocation ha;
4045 ASSERT(args.length() == 2);
4046
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004047 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004049 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004050 }
4051 if (isinf(value)) {
4052 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004053 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004055 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004057 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004058 int f = FastD2I(f_number);
4059 RUNTIME_ASSERT(f >= -1 && f <= 20);
4060 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004061 MaybeObject* res =
4062 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004064 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065}
4066
4067
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004068RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 NoHandleAllocation ha;
4070 ASSERT(args.length() == 2);
4071
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004072 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004073 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004074 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 }
4076 if (isinf(value)) {
4077 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004078 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004079 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004080 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004082 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004083 int f = FastD2I(f_number);
4084 RUNTIME_ASSERT(f >= 1 && f <= 21);
4085 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004086 MaybeObject* res =
4087 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004089 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004090}
4091
4092
4093// Returns a single character string where first character equals
4094// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004095static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004096 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004097 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004098 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004099 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004101 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102}
4103
4104
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004105MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4106 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004107 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108 // Handle [] indexing on Strings
4109 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004110 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4111 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 }
4113
4114 // Handle [] indexing on String objects
4115 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004116 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4117 Handle<Object> result =
4118 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4119 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004120 }
4121
4122 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004123 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004124 return prototype->GetElement(index);
4125 }
4126
4127 return object->GetElement(index);
4128}
4129
4130
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004131MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4132 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004133 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004134 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004135
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004136 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004137 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004138 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004139 isolate->factory()->NewTypeError("non_object_property_load",
4140 HandleVector(args, 2));
4141 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004142 }
4143
4144 // Check if the given key is an array index.
4145 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004146 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004147 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004148 }
4149
4150 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004151 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004152 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004153 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004154 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155 bool has_pending_exception = false;
4156 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004157 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004158 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004159 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160 }
4161
ager@chromium.org32912102009-01-16 10:38:43 +00004162 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004163 // the element if so.
4164 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004165 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004167 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004168 }
4169}
4170
4171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004172RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 NoHandleAllocation ha;
4174 ASSERT(args.length() == 2);
4175
4176 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004177 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004178
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004179 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004180}
4181
4182
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004183MaybeObject* TransitionElements(Handle<Object> object,
4184 ElementsKind to_kind,
4185 Isolate* isolate) {
4186 HandleScope scope(isolate);
4187 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4188 ElementsKind from_kind =
4189 Handle<JSObject>::cast(object)->map()->elements_kind();
4190 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
4191 Handle<Object> result =
4192 TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
4193 if (result.is_null()) return isolate->ThrowIllegalOperation();
4194 return *result;
4195 }
4196 return isolate->ThrowIllegalOperation();
4197}
4198
4199
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004200// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004201RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004202 NoHandleAllocation ha;
4203 ASSERT(args.length() == 2);
4204
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004205 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004206 // itself.
4207 //
4208 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004209 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004210 // global proxy object never has properties. This is the case
4211 // because the global proxy object forwards everything to its hidden
4212 // prototype including local lookups.
4213 //
4214 // Additionally, we need to make sure that we do not cache results
4215 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004216 if (args[0]->IsJSObject()) {
4217 if (!args[0]->IsJSGlobalProxy() &&
4218 !args[0]->IsAccessCheckNeeded() &&
4219 args[1]->IsString()) {
4220 JSObject* receiver = JSObject::cast(args[0]);
4221 String* key = String::cast(args[1]);
4222 if (receiver->HasFastProperties()) {
4223 // Attempt to use lookup cache.
4224 Map* receiver_map = receiver->map();
4225 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4226 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4227 if (offset != -1) {
4228 Object* value = receiver->FastPropertyAt(offset);
4229 return value->IsTheHole()
4230 ? isolate->heap()->undefined_value()
4231 : value;
4232 }
4233 // Lookup cache miss. Perform lookup and update the cache if
4234 // appropriate.
4235 LookupResult result(isolate);
4236 receiver->LocalLookup(key, &result);
4237 if (result.IsProperty() && result.type() == FIELD) {
4238 int offset = result.GetFieldIndex();
4239 keyed_lookup_cache->Update(receiver_map, key, offset);
4240 return receiver->FastPropertyAt(offset);
4241 }
4242 } else {
4243 // Attempt dictionary lookup.
4244 StringDictionary* dictionary = receiver->property_dictionary();
4245 int entry = dictionary->FindEntry(key);
4246 if ((entry != StringDictionary::kNotFound) &&
4247 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4248 Object* value = dictionary->ValueAt(entry);
4249 if (!receiver->IsGlobalObject()) return value;
4250 value = JSGlobalPropertyCell::cast(value)->value();
4251 if (!value->IsTheHole()) return value;
4252 // If value is the hole do the general lookup.
4253 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004254 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004255 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4256 // JSObject without a string key. If the key is a Smi, check for a
4257 // definite out-of-bounds access to elements, which is a strong indicator
4258 // that subsequent accesses will also call the runtime. Proactively
4259 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4260 // doubles for those future calls in the case that the elements would
4261 // become FAST_DOUBLE_ELEMENTS.
4262 Handle<JSObject> js_object(args.at<JSObject>(0));
4263 ElementsKind elements_kind = js_object->GetElementsKind();
4264 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4265 elements_kind == FAST_DOUBLE_ELEMENTS) {
4266 FixedArrayBase* elements = js_object->elements();
4267 if (args.at<Smi>(1)->value() >= elements->length()) {
4268 MaybeObject* maybe_object = TransitionElements(js_object,
4269 FAST_ELEMENTS,
4270 isolate);
4271 if (maybe_object->IsFailure()) return maybe_object;
4272 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004273 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004274 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004275 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4276 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004277 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004278 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004279 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004280 if (index >= 0 && index < str->length()) {
4281 Handle<Object> result = GetCharAt(str, index);
4282 return *result;
4283 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004284 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004285
4286 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004287 return Runtime::GetObjectProperty(isolate,
4288 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004289 args.at<Object>(1));
4290}
4291
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004292// Implements part of 8.12.9 DefineOwnProperty.
4293// There are 3 cases that lead here:
4294// Step 4b - define a new accessor property.
4295// Steps 9c & 12 - replace an existing data property with an accessor property.
4296// Step 12 - update an existing accessor property with an accessor or generic
4297// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004298RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004299 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004300 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004301 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4302 CONVERT_CHECKED(String, name, args[1]);
4303 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004304 Object* fun = args[3];
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004305 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004306 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4307 int unchecked = flag_attr->value();
4308 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4309 RUNTIME_ASSERT(!obj->IsNull());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004310 LookupResult result(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004311 obj->LocalLookupRealNamedProperty(name, &result);
4312
4313 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4314 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4315 // delete it to avoid running into trouble in DefineAccessor, which
4316 // handles this incorrectly if the property is readonly (does nothing)
4317 if (result.IsProperty() &&
4318 (result.type() == FIELD || result.type() == NORMAL
4319 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004320 Object* ok;
4321 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004322 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004323 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4324 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004325 }
4326 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4327}
4328
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004329// Implements part of 8.12.9 DefineOwnProperty.
4330// There are 3 cases that lead here:
4331// Step 4a - define a new data property.
4332// Steps 9b & 12 - replace an existing accessor property with a data property.
4333// Step 12 - update an existing data property with a data or generic
4334// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004335RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004336 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004338 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4339 CONVERT_ARG_CHECKED(String, name, 1);
4340 Handle<Object> obj_value = args.at<Object>(2);
4341
4342 CONVERT_CHECKED(Smi, flag, args[3]);
4343 int unchecked = flag->value();
4344 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4345
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004346 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4347
4348 // Check if this is an element.
4349 uint32_t index;
4350 bool is_element = name->AsArrayIndex(&index);
4351
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004352 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004353 // If elements are in fast case we always implicitly assume that:
4354 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004355 if (is_element && (attr != NONE ||
4356 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004357 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004358 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004359 // We do not need to do access checks here since these has already
4360 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004361 Handle<Object> proto(js_object->GetPrototype());
4362 // If proxy is detached, ignore the assignment. Alternatively,
4363 // we could throw an exception.
4364 if (proto->IsNull()) return *obj_value;
4365 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004366 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004367
4368 // Don't allow element properties to be redefined on objects with external
4369 // array elements.
4370 if (js_object->HasExternalArrayElements()) {
4371 Handle<Object> args[2] = { js_object, name };
4372 Handle<Object> error =
4373 isolate->factory()->NewTypeError("redef_external_array_element",
4374 HandleVector(args, 2));
4375 return isolate->Throw(*error);
4376 }
4377
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004378 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004379 // Make sure that we never go back to fast case.
4380 dictionary->set_requires_slow_elements();
4381 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004382 Handle<NumberDictionary> extended_dictionary =
4383 NumberDictionarySet(dictionary, index, obj_value, details);
4384 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004385 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004386 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4387 } else {
4388 js_object->set_elements(*extended_dictionary);
4389 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004390 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004391 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004392 }
4393
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004394 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004395 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004396
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004397 // To be compatible with safari we do not change the value on API objects
4398 // in defineProperty. Firefox disagrees here, and actually changes the value.
4399 if (result.IsProperty() &&
4400 (result.type() == CALLBACKS) &&
4401 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004402 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004403 }
4404
ager@chromium.org5c838252010-02-19 08:53:10 +00004405 // Take special care when attributes are different and there is already
4406 // a property. For simplicity we normalize the property which enables us
4407 // to not worry about changing the instance_descriptor and creating a new
4408 // map. The current version of SetObjectProperty does not handle attributes
4409 // correctly in the case where a property is a field and is reset with
4410 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004411 if (result.IsProperty() &&
4412 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004413 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004414 if (js_object->IsJSGlobalProxy()) {
4415 // Since the result is a property, the prototype will exist so
4416 // we don't have to check for null.
4417 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004418 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004419 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004420 // Use IgnoreAttributes version since a readonly property may be
4421 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004422 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4423 *obj_value,
4424 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004425 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004427 return Runtime::ForceSetObjectProperty(isolate,
4428 js_object,
4429 name,
4430 obj_value,
4431 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004432}
4433
4434
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004435// Special case for elements if any of the flags are true.
4436// If elements are in fast case we always implicitly assume that:
4437// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4438static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4439 Handle<JSObject> js_object,
4440 uint32_t index,
4441 Handle<Object> value,
4442 PropertyAttributes attr) {
4443 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004444 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004445 // Make sure that we never go back to fast case.
4446 dictionary->set_requires_slow_elements();
4447 PropertyDetails details = PropertyDetails(attr, NORMAL);
4448 Handle<NumberDictionary> extended_dictionary =
4449 NumberDictionarySet(dictionary, index, value, details);
4450 if (*extended_dictionary != *dictionary) {
4451 js_object->set_elements(*extended_dictionary);
4452 }
4453 return *value;
4454}
4455
4456
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004457MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4458 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004459 Handle<Object> key,
4460 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004461 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004462 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004463 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004464
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004465 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004466 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004468 isolate->factory()->NewTypeError("non_object_property_store",
4469 HandleVector(args, 2));
4470 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004471 }
4472
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004473 if (object->IsJSProxy()) {
4474 bool has_pending_exception = false;
4475 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4476 if (has_pending_exception) return Failure::Exception();
4477 return JSProxy::cast(*object)->SetProperty(
4478 String::cast(*name), *value, attr, strict_mode);
4479 }
4480
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 // If the object isn't a JavaScript object, we ignore the store.
4482 if (!object->IsJSObject()) return *value;
4483
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004484 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4485
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004486 // Check if the given key is an array index.
4487 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004488 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004489 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4490 // of a string using [] notation. We need to support this too in
4491 // JavaScript.
4492 // In the case of a String object we just need to redirect the assignment to
4493 // the underlying string if the index is in range. Since the underlying
4494 // string does nothing with the assignment then we can ignore such
4495 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004496 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004497 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004498 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004500 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4501 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4502 }
4503
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004504 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004505 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004506 return *value;
4507 }
4508
4509 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004510 Handle<Object> result;
4511 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004512 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4513 return NormalizeObjectSetElement(isolate,
4514 js_object,
4515 index,
4516 value,
4517 attr);
4518 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004519 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004520 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004521 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004522 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004523 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004524 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004525 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004526 return *value;
4527 }
4528
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004529 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004530 bool has_pending_exception = false;
4531 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4532 if (has_pending_exception) return Failure::Exception();
4533 Handle<String> name = Handle<String>::cast(converted);
4534
4535 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004536 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004537 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004538 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004539 }
4540}
4541
4542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004543MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4544 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004545 Handle<Object> key,
4546 Handle<Object> value,
4547 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004548 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004549
4550 // Check if the given key is an array index.
4551 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004552 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004553 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4554 // of a string using [] notation. We need to support this too in
4555 // JavaScript.
4556 // In the case of a String object we just need to redirect the assignment to
4557 // the underlying string if the index is in range. Since the underlying
4558 // string does nothing with the assignment then we can ignore such
4559 // assignments.
4560 if (js_object->IsStringObjectWithCharacterAt(index)) {
4561 return *value;
4562 }
4563
whesse@chromium.org7b260152011-06-20 15:33:18 +00004564 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004565 }
4566
4567 if (key->IsString()) {
4568 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004569 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004570 } else {
4571 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004572 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004573 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4574 *value,
4575 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004576 }
4577 }
4578
4579 // Call-back into JavaScript to convert the key to a string.
4580 bool has_pending_exception = false;
4581 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4582 if (has_pending_exception) return Failure::Exception();
4583 Handle<String> name = Handle<String>::cast(converted);
4584
4585 if (name->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 {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004588 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004589 }
4590}
4591
4592
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004593MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004594 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004595 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004596 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004597
4598 // Check if the given key is an array index.
4599 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004600 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004601 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4602 // characters of a string using [] notation. In the case of a
4603 // String object we just need to redirect the deletion to the
4604 // underlying string if the index is in range. Since the
4605 // underlying string does nothing with the deletion, we can ignore
4606 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004607 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004608 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004609 }
4610
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004611 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004612 }
4613
4614 Handle<String> key_string;
4615 if (key->IsString()) {
4616 key_string = Handle<String>::cast(key);
4617 } else {
4618 // Call-back into JavaScript to convert the key to a string.
4619 bool has_pending_exception = false;
4620 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4621 if (has_pending_exception) return Failure::Exception();
4622 key_string = Handle<String>::cast(converted);
4623 }
4624
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004625 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004626 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004627}
4628
4629
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004630RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004631 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004632 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004633
4634 Handle<Object> object = args.at<Object>(0);
4635 Handle<Object> key = args.at<Object>(1);
4636 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004637 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004638 RUNTIME_ASSERT(
4639 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004640 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004641 PropertyAttributes attributes =
4642 static_cast<PropertyAttributes>(unchecked_attributes);
4643
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004644 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004645 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004646 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4647 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004648 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004649
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004650 return Runtime::SetObjectProperty(isolate,
4651 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004652 key,
4653 value,
4654 attributes,
4655 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004656}
4657
4658
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004659RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4660 NoHandleAllocation ha;
4661 RUNTIME_ASSERT(args.length() == 1);
4662 Handle<Object> object = args.at<Object>(0);
4663 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4664}
4665
4666
4667RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4668 NoHandleAllocation ha;
4669 RUNTIME_ASSERT(args.length() == 1);
4670 Handle<Object> object = args.at<Object>(0);
4671 return TransitionElements(object, FAST_ELEMENTS, isolate);
4672}
4673
4674
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004675// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004676// This is used to decide if we should transform null and undefined
4677// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004678RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004679 NoHandleAllocation ha;
4680 RUNTIME_ASSERT(args.length() == 1);
4681
4682 Handle<Object> object = args.at<Object>(0);
4683
4684 if (object->IsJSFunction()) {
4685 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004686 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004687 }
4688 return isolate->heap()->undefined_value();
4689}
4690
4691
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004692RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4693 RUNTIME_ASSERT(args.length() == 5);
4694 CONVERT_ARG_CHECKED(JSObject, object, 0);
4695 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4696 Handle<Object> value = args.at<Object>(2);
4697 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4698 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4699 HandleScope scope;
4700
4701 Object* raw_boilerplate_object = literals->get(literal_index);
4702 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4703#if DEBUG
4704 ElementsKind elements_kind = object->GetElementsKind();
4705#endif
4706 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4707 // Smis should never trigger transitions.
4708 ASSERT(!value->IsSmi());
4709
4710 if (value->IsNumber()) {
4711 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
4712 TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4713 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4714 FixedDoubleArray* double_array =
4715 FixedDoubleArray::cast(object->elements());
4716 HeapNumber* number = HeapNumber::cast(*value);
4717 double_array->set(store_index, number->Number());
4718 } else {
4719 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4720 elements_kind == FAST_DOUBLE_ELEMENTS);
4721 TransitionElementsKind(object, FAST_ELEMENTS);
4722 FixedArray* object_array =
4723 FixedArray::cast(object->elements());
4724 object_array->set(store_index, *value);
4725 }
4726 return *object;
4727}
4728
4729
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004730// Set a local property, even if it is READ_ONLY. If the property does not
4731// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004732RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004733 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004734 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004735 CONVERT_CHECKED(JSObject, object, args[0]);
4736 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004737 // Compute attributes.
4738 PropertyAttributes attributes = NONE;
4739 if (args.length() == 4) {
4740 CONVERT_CHECKED(Smi, value_obj, args[3]);
4741 int unchecked_value = value_obj->value();
4742 // Only attribute bits should be set.
4743 RUNTIME_ASSERT(
4744 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4745 attributes = static_cast<PropertyAttributes>(unchecked_value);
4746 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004748 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004749 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004750}
4751
4752
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004753RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004754 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004755 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004757 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004758 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004759 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004760 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004761 ? JSReceiver::STRICT_DELETION
4762 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004763}
4764
4765
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004766static Object* HasLocalPropertyImplementation(Isolate* isolate,
4767 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004768 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004769 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004770 // Handle hidden prototypes. If there's a hidden prototype above this thing
4771 // then we have to check it for properties, because they are supposed to
4772 // look like they are on this object.
4773 Handle<Object> proto(object->GetPrototype());
4774 if (proto->IsJSObject() &&
4775 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004776 return HasLocalPropertyImplementation(isolate,
4777 Handle<JSObject>::cast(proto),
4778 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004779 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004780 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004781}
4782
4783
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004784RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785 NoHandleAllocation ha;
4786 ASSERT(args.length() == 2);
4787 CONVERT_CHECKED(String, key, args[1]);
4788
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004789 uint32_t index;
4790 const bool key_is_array_index = key->AsArrayIndex(&index);
4791
ager@chromium.org9085a012009-05-11 19:22:57 +00004792 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004794 if (obj->IsJSObject()) {
4795 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004796 // Fast case: either the key is a real named property or it is not
4797 // an array index and there are no interceptors or hidden
4798 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004799 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004800 Map* map = object->map();
4801 if (!key_is_array_index &&
4802 !map->has_named_interceptor() &&
4803 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4804 return isolate->heap()->false_value();
4805 }
4806 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004807 HandleScope scope(isolate);
4808 return HasLocalPropertyImplementation(isolate,
4809 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004810 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004811 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004812 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004813 String* string = String::cast(obj);
4814 if (index < static_cast<uint32_t>(string->length())) {
4815 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004816 }
4817 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004818 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004819}
4820
4821
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004822RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004823 NoHandleAllocation na;
4824 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004825 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4826 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004828 bool result = receiver->HasProperty(key);
4829 if (isolate->has_pending_exception()) return Failure::Exception();
4830 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831}
4832
4833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004834RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004835 NoHandleAllocation na;
4836 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004837 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4838 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004839
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004840 bool result = receiver->HasElement(index->value());
4841 if (isolate->has_pending_exception()) return Failure::Exception();
4842 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843}
4844
4845
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004846RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847 NoHandleAllocation ha;
4848 ASSERT(args.length() == 2);
4849
4850 CONVERT_CHECKED(JSObject, object, args[0]);
4851 CONVERT_CHECKED(String, key, args[1]);
4852
4853 uint32_t index;
4854 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004855 JSObject::LocalElementType type = object->HasLocalElement(index);
4856 switch (type) {
4857 case JSObject::UNDEFINED_ELEMENT:
4858 case JSObject::STRING_CHARACTER_ELEMENT:
4859 return isolate->heap()->false_value();
4860 case JSObject::INTERCEPTED_ELEMENT:
4861 case JSObject::FAST_ELEMENT:
4862 return isolate->heap()->true_value();
4863 case JSObject::DICTIONARY_ELEMENT: {
4864 if (object->IsJSGlobalProxy()) {
4865 Object* proto = object->GetPrototype();
4866 if (proto->IsNull()) {
4867 return isolate->heap()->false_value();
4868 }
4869 ASSERT(proto->IsJSGlobalObject());
4870 object = JSObject::cast(proto);
4871 }
4872 FixedArray* elements = FixedArray::cast(object->elements());
4873 NumberDictionary* dictionary = NULL;
4874 if (elements->map() ==
4875 isolate->heap()->non_strict_arguments_elements_map()) {
4876 dictionary = NumberDictionary::cast(elements->get(1));
4877 } else {
4878 dictionary = NumberDictionary::cast(elements);
4879 }
4880 int entry = dictionary->FindEntry(index);
4881 ASSERT(entry != NumberDictionary::kNotFound);
4882 PropertyDetails details = dictionary->DetailsAt(entry);
4883 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4884 }
4885 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004886 }
4887
ager@chromium.org870a0b62008-11-04 11:43:05 +00004888 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004889 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890}
4891
4892
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004893RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004894 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004895 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004896 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4897 bool threw = false;
4898 Handle<JSArray> result = GetKeysFor(object, &threw);
4899 if (threw) return Failure::Exception();
4900 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004901}
4902
4903
4904// Returns either a FixedArray as Runtime_GetPropertyNames,
4905// or, if the given object has an enum cache that contains
4906// all enumerable properties of the object and its prototypes
4907// have none, the map of the object. This is used to speed up
4908// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004909RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004910 ASSERT(args.length() == 1);
4911
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004912 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004913
4914 if (raw_object->IsSimpleEnum()) return raw_object->map();
4915
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004916 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004917 Handle<JSReceiver> object(raw_object);
4918 bool threw = false;
4919 Handle<FixedArray> content =
4920 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4921 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004922
4923 // Test again, since cache may have been built by preceding call.
4924 if (object->IsSimpleEnum()) return object->map();
4925
4926 return *content;
4927}
4928
4929
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004930// Find the length of the prototype chain that is to to handled as one. If a
4931// prototype object is hidden it is to be viewed as part of the the object it
4932// is prototype for.
4933static int LocalPrototypeChainLength(JSObject* obj) {
4934 int count = 1;
4935 Object* proto = obj->GetPrototype();
4936 while (proto->IsJSObject() &&
4937 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4938 count++;
4939 proto = JSObject::cast(proto)->GetPrototype();
4940 }
4941 return count;
4942}
4943
4944
4945// Return the names of the local named properties.
4946// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004947RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004948 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004949 ASSERT(args.length() == 1);
4950 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004951 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004952 }
4953 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4954
4955 // Skip the global proxy as it has no properties and always delegates to the
4956 // real global object.
4957 if (obj->IsJSGlobalProxy()) {
4958 // Only collect names if access is permitted.
4959 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004960 !isolate->MayNamedAccess(*obj,
4961 isolate->heap()->undefined_value(),
4962 v8::ACCESS_KEYS)) {
4963 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4964 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004965 }
4966 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4967 }
4968
4969 // Find the number of objects making up this.
4970 int length = LocalPrototypeChainLength(*obj);
4971
4972 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004973 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004974 int total_property_count = 0;
4975 Handle<JSObject> jsproto = obj;
4976 for (int i = 0; i < length; i++) {
4977 // Only collect names if access is permitted.
4978 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004979 !isolate->MayNamedAccess(*jsproto,
4980 isolate->heap()->undefined_value(),
4981 v8::ACCESS_KEYS)) {
4982 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4983 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004984 }
4985 int n;
4986 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4987 local_property_count[i] = n;
4988 total_property_count += n;
4989 if (i < length - 1) {
4990 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4991 }
4992 }
4993
4994 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004995 Handle<FixedArray> names =
4996 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004997
4998 // Get the property names.
4999 jsproto = obj;
5000 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005001 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005002 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005003 jsproto->GetLocalPropertyNames(*names, next_copy_index);
5004 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005005 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005006 proto_with_hidden_properties++;
5007 }
5008 if (i < length - 1) {
5009 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5010 }
5011 }
5012
5013 // Filter out name of hidden propeties object.
5014 if (proto_with_hidden_properties > 0) {
5015 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005016 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005017 names->length() - proto_with_hidden_properties);
5018 int dest_pos = 0;
5019 for (int i = 0; i < total_property_count; i++) {
5020 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005021 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005022 continue;
5023 }
5024 names->set(dest_pos++, name);
5025 }
5026 }
5027
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005028 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005029}
5030
5031
5032// Return the names of the local indexed properties.
5033// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005034RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005035 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005036 ASSERT(args.length() == 1);
5037 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005038 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005039 }
5040 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5041
5042 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005043 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005044 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005045 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005046}
5047
5048
5049// Return information on whether an object has a named or indexed interceptor.
5050// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005051RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005052 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005053 ASSERT(args.length() == 1);
5054 if (!args[0]->IsJSObject()) {
5055 return Smi::FromInt(0);
5056 }
5057 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5058
5059 int result = 0;
5060 if (obj->HasNamedInterceptor()) result |= 2;
5061 if (obj->HasIndexedInterceptor()) result |= 1;
5062
5063 return Smi::FromInt(result);
5064}
5065
5066
5067// Return property names from named interceptor.
5068// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005069RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005070 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005071 ASSERT(args.length() == 1);
5072 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5073
5074 if (obj->HasNamedInterceptor()) {
5075 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5076 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5077 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005078 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005079}
5080
5081
5082// Return element names from indexed interceptor.
5083// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005084RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005085 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005086 ASSERT(args.length() == 1);
5087 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5088
5089 if (obj->HasIndexedInterceptor()) {
5090 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5091 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5092 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005093 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005094}
5095
5096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005097RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005098 ASSERT_EQ(args.length(), 1);
5099 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005100 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005101 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005102
5103 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005104 // Do access checks before going to the global object.
5105 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005106 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005107 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005108 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5109 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005110 }
5111
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005112 Handle<Object> proto(object->GetPrototype());
5113 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005114 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005115 object = Handle<JSObject>::cast(proto);
5116 }
5117
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005118 bool threw = false;
5119 Handle<FixedArray> contents =
5120 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5121 if (threw) return Failure::Exception();
5122
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005123 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5124 // property array and since the result is mutable we have to create
5125 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005126 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005127 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005128 for (int i = 0; i < length; i++) {
5129 Object* entry = contents->get(i);
5130 if (entry->IsString()) {
5131 copy->set(i, entry);
5132 } else {
5133 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005134 HandleScope scope(isolate);
5135 Handle<Object> entry_handle(entry, isolate);
5136 Handle<Object> entry_str =
5137 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005138 copy->set(i, *entry_str);
5139 }
5140 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005141 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005142}
5143
5144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005145RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005146 NoHandleAllocation ha;
5147 ASSERT(args.length() == 1);
5148
5149 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005150 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005151 it.AdvanceToArgumentsFrame();
5152 JavaScriptFrame* frame = it.frame();
5153
5154 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005155 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005156
5157 // Try to convert the key to an index. If successful and within
5158 // index return the the argument from the frame.
5159 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005160 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005161 return frame->GetParameter(index);
5162 }
5163
5164 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005166 bool exception = false;
5167 Handle<Object> converted =
5168 Execution::ToString(args.at<Object>(0), &exception);
5169 if (exception) return Failure::Exception();
5170 Handle<String> key = Handle<String>::cast(converted);
5171
5172 // Try to convert the string key into an array index.
5173 if (key->AsArrayIndex(&index)) {
5174 if (index < n) {
5175 return frame->GetParameter(index);
5176 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005177 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005178 }
5179 }
5180
5181 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005182 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5183 if (key->Equals(isolate->heap()->callee_symbol())) {
5184 Object* function = frame->function();
5185 if (function->IsJSFunction() &&
5186 JSFunction::cast(function)->shared()->strict_mode()) {
5187 return isolate->Throw(*isolate->factory()->NewTypeError(
5188 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5189 }
5190 return function;
5191 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005192
5193 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005194 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195}
5196
5197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005198RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005199 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005200
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005201 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005202 Handle<Object> object = args.at<Object>(0);
5203 if (object->IsJSObject()) {
5204 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005205 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005206 MaybeObject* ok = js_object->TransformToFastProperties(0);
5207 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005208 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005209 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005210 return *object;
5211}
5212
5213
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005214RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005216
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005217 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005218 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005219 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005220 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005221 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005222 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005223 return *object;
5224}
5225
5226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005227RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 NoHandleAllocation ha;
5229 ASSERT(args.length() == 1);
5230
5231 return args[0]->ToBoolean();
5232}
5233
5234
5235// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5236// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005237RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005238 NoHandleAllocation ha;
5239
5240 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005241 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005242 HeapObject* heap_obj = HeapObject::cast(obj);
5243
5244 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005245 if (heap_obj->map()->is_undetectable()) {
5246 return isolate->heap()->undefined_symbol();
5247 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005248
5249 InstanceType instance_type = heap_obj->map()->instance_type();
5250 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005251 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005252 }
5253
5254 switch (instance_type) {
5255 case ODDBALL_TYPE:
5256 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005257 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005258 }
5259 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005260 return FLAG_harmony_typeof
5261 ? isolate->heap()->null_symbol()
5262 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005263 }
5264 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005265 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005266 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005267 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005268 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005269 default:
5270 // For any kind of object not handled above, the spec rule for
5271 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005272 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005273 }
5274}
5275
5276
lrn@chromium.org25156de2010-04-06 13:10:27 +00005277static bool AreDigits(const char*s, int from, int to) {
5278 for (int i = from; i < to; i++) {
5279 if (s[i] < '0' || s[i] > '9') return false;
5280 }
5281
5282 return true;
5283}
5284
5285
5286static int ParseDecimalInteger(const char*s, int from, int to) {
5287 ASSERT(to - from < 10); // Overflow is not possible.
5288 ASSERT(from < to);
5289 int d = s[from] - '0';
5290
5291 for (int i = from + 1; i < to; i++) {
5292 d = 10 * d + (s[i] - '0');
5293 }
5294
5295 return d;
5296}
5297
5298
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005299RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005300 NoHandleAllocation ha;
5301 ASSERT(args.length() == 1);
5302 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005303 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005304
5305 // Fast case: short integer or some sorts of junk values.
5306 int len = subject->length();
5307 if (subject->IsSeqAsciiString()) {
5308 if (len == 0) return Smi::FromInt(0);
5309
5310 char const* data = SeqAsciiString::cast(subject)->GetChars();
5311 bool minus = (data[0] == '-');
5312 int start_pos = (minus ? 1 : 0);
5313
5314 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005315 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005316 } else if (data[start_pos] > '9') {
5317 // Fast check for a junk value. A valid string may start from a
5318 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5319 // the 'I' character ('Infinity'). All of that have codes not greater than
5320 // '9' except 'I'.
5321 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005322 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005323 }
5324 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5325 // The maximal/minimal smi has 10 digits. If the string has less digits we
5326 // know it will fit into the smi-data type.
5327 int d = ParseDecimalInteger(data, start_pos, len);
5328 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005329 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005330 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005331 } else if (!subject->HasHashCode() &&
5332 len <= String::kMaxArrayIndexSize &&
5333 (len == 1 || data[0] != '0')) {
5334 // String hash is not calculated yet but all the data are present.
5335 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005336 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005337#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005338 subject->Hash(); // Force hash calculation.
5339 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5340 static_cast<int>(hash));
5341#endif
5342 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005343 }
5344 return Smi::FromInt(d);
5345 }
5346 }
5347
5348 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005349 return isolate->heap()->NumberFromDouble(
5350 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005351}
5352
5353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005354RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005355 NoHandleAllocation ha;
5356 ASSERT(args.length() == 1);
5357
5358 CONVERT_CHECKED(JSArray, codes, args[0]);
5359 int length = Smi::cast(codes->length())->value();
5360
5361 // Check if the string can be ASCII.
5362 int i;
5363 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005364 Object* element;
5365 { MaybeObject* maybe_element = codes->GetElement(i);
5366 // We probably can't get an exception here, but just in order to enforce
5367 // the checking of inputs in the runtime calls we check here.
5368 if (!maybe_element->ToObject(&element)) return maybe_element;
5369 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5371 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5372 break;
5373 }
5374
lrn@chromium.org303ada72010-10-27 09:33:13 +00005375 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005376 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005377 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005378 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005379 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005380 }
5381
lrn@chromium.org303ada72010-10-27 09:33:13 +00005382 Object* object = NULL;
5383 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005384 String* result = String::cast(object);
5385 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005386 Object* element;
5387 { MaybeObject* maybe_element = codes->GetElement(i);
5388 if (!maybe_element->ToObject(&element)) return maybe_element;
5389 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005390 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005391 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005392 }
5393 return result;
5394}
5395
5396
5397// kNotEscaped is generated by the following:
5398//
5399// #!/bin/perl
5400// for (my $i = 0; $i < 256; $i++) {
5401// print "\n" if $i % 16 == 0;
5402// my $c = chr($i);
5403// my $escaped = 1;
5404// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5405// print $escaped ? "0, " : "1, ";
5406// }
5407
5408
5409static bool IsNotEscaped(uint16_t character) {
5410 // Only for 8 bit characters, the rest are always escaped (in a different way)
5411 ASSERT(character < 256);
5412 static const char kNotEscaped[256] = {
5413 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5415 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5416 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5417 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5418 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5419 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5420 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
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, 0, 0, 0, 0, 0, 0,
5424 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5425 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5426 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5427 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5428 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5429 };
5430 return kNotEscaped[character] != 0;
5431}
5432
5433
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005434RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005435 const char hex_chars[] = "0123456789ABCDEF";
5436 NoHandleAllocation ha;
5437 ASSERT(args.length() == 1);
5438 CONVERT_CHECKED(String, source, args[0]);
5439
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005440 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005441
5442 int escaped_length = 0;
5443 int length = source->length();
5444 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005445 Access<StringInputBuffer> buffer(
5446 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005447 buffer->Reset(source);
5448 while (buffer->has_more()) {
5449 uint16_t character = buffer->GetNext();
5450 if (character >= 256) {
5451 escaped_length += 6;
5452 } else if (IsNotEscaped(character)) {
5453 escaped_length++;
5454 } else {
5455 escaped_length += 3;
5456 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005457 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005458 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005459 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005460 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005461 return Failure::OutOfMemoryException();
5462 }
5463 }
5464 }
5465 // No length change implies no change. Return original string if no change.
5466 if (escaped_length == length) {
5467 return source;
5468 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005469 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005470 { MaybeObject* maybe_o =
5471 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005472 if (!maybe_o->ToObject(&o)) return maybe_o;
5473 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474 String* destination = String::cast(o);
5475 int dest_position = 0;
5476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005477 Access<StringInputBuffer> buffer(
5478 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 buffer->Rewind();
5480 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005481 uint16_t chr = buffer->GetNext();
5482 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005483 destination->Set(dest_position, '%');
5484 destination->Set(dest_position+1, 'u');
5485 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5486 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5487 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5488 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005490 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005491 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005492 dest_position++;
5493 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005494 destination->Set(dest_position, '%');
5495 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5496 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497 dest_position += 3;
5498 }
5499 }
5500 return destination;
5501}
5502
5503
5504static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5505 static const signed char kHexValue['g'] = {
5506 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5507 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5508 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5509 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5510 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5511 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5512 -1, 10, 11, 12, 13, 14, 15 };
5513
5514 if (character1 > 'f') return -1;
5515 int hi = kHexValue[character1];
5516 if (hi == -1) return -1;
5517 if (character2 > 'f') return -1;
5518 int lo = kHexValue[character2];
5519 if (lo == -1) return -1;
5520 return (hi << 4) + lo;
5521}
5522
5523
ager@chromium.org870a0b62008-11-04 11:43:05 +00005524static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005525 int i,
5526 int length,
5527 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005528 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005529 int32_t hi = 0;
5530 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005531 if (character == '%' &&
5532 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005533 source->Get(i + 1) == 'u' &&
5534 (hi = TwoDigitHex(source->Get(i + 2),
5535 source->Get(i + 3))) != -1 &&
5536 (lo = TwoDigitHex(source->Get(i + 4),
5537 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005538 *step = 6;
5539 return (hi << 8) + lo;
5540 } else if (character == '%' &&
5541 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005542 (lo = TwoDigitHex(source->Get(i + 1),
5543 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005544 *step = 3;
5545 return lo;
5546 } else {
5547 *step = 1;
5548 return character;
5549 }
5550}
5551
5552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005553RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005554 NoHandleAllocation ha;
5555 ASSERT(args.length() == 1);
5556 CONVERT_CHECKED(String, source, args[0]);
5557
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005558 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005559
5560 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005561 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005562
5563 int unescaped_length = 0;
5564 for (int i = 0; i < length; unescaped_length++) {
5565 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005566 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005567 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005568 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005569 i += step;
5570 }
5571
5572 // No length change implies no change. Return original string if no change.
5573 if (unescaped_length == length)
5574 return source;
5575
lrn@chromium.org303ada72010-10-27 09:33:13 +00005576 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005577 { MaybeObject* maybe_o =
5578 ascii ?
5579 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5580 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005581 if (!maybe_o->ToObject(&o)) return maybe_o;
5582 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005583 String* destination = String::cast(o);
5584
5585 int dest_position = 0;
5586 for (int i = 0; i < length; dest_position++) {
5587 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005588 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005589 i += step;
5590 }
5591 return destination;
5592}
5593
5594
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005595static const unsigned int kQuoteTableLength = 128u;
5596
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005597static const int kJsonQuotesCharactersPerEntry = 8;
5598static const char* const JsonQuotes =
5599 "\\u0000 \\u0001 \\u0002 \\u0003 "
5600 "\\u0004 \\u0005 \\u0006 \\u0007 "
5601 "\\b \\t \\n \\u000b "
5602 "\\f \\r \\u000e \\u000f "
5603 "\\u0010 \\u0011 \\u0012 \\u0013 "
5604 "\\u0014 \\u0015 \\u0016 \\u0017 "
5605 "\\u0018 \\u0019 \\u001a \\u001b "
5606 "\\u001c \\u001d \\u001e \\u001f "
5607 " ! \\\" # "
5608 "$ % & ' "
5609 "( ) * + "
5610 ", - . / "
5611 "0 1 2 3 "
5612 "4 5 6 7 "
5613 "8 9 : ; "
5614 "< = > ? "
5615 "@ A B C "
5616 "D E F G "
5617 "H I J K "
5618 "L M N O "
5619 "P Q R S "
5620 "T U V W "
5621 "X Y Z [ "
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 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005631
5632
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005633// For a string that is less than 32k characters it should always be
5634// possible to allocate it in new space.
5635static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5636
5637
5638// Doing JSON quoting cannot make the string more than this many times larger.
5639static const int kJsonQuoteWorstCaseBlowup = 6;
5640
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005641static const int kSpaceForQuotesAndComma = 3;
5642static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005643
5644// Covers the entire ASCII range (all other characters are unchanged by JSON
5645// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005646static const byte JsonQuoteLengths[kQuoteTableLength] = {
5647 6, 6, 6, 6, 6, 6, 6, 6,
5648 2, 2, 2, 6, 2, 2, 6, 6,
5649 6, 6, 6, 6, 6, 6, 6, 6,
5650 6, 6, 6, 6, 6, 6, 6, 6,
5651 1, 1, 2, 1, 1, 1, 1, 1,
5652 1, 1, 1, 1, 1, 1, 1, 1,
5653 1, 1, 1, 1, 1, 1, 1, 1,
5654 1, 1, 1, 1, 1, 1, 1, 1,
5655 1, 1, 1, 1, 1, 1, 1, 1,
5656 1, 1, 1, 1, 1, 1, 1, 1,
5657 1, 1, 1, 1, 1, 1, 1, 1,
5658 1, 1, 1, 1, 2, 1, 1, 1,
5659 1, 1, 1, 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};
5664
5665
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005666template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005667MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005668
5669
5670template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005671MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5672 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005673}
5674
5675
5676template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005677MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5678 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005679}
5680
5681
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005682template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005683static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5684 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005685 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005686 const Char* read_cursor = characters.start();
5687 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005688 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005689 int quoted_length = kSpaceForQuotes;
5690 while (read_cursor < end) {
5691 Char c = *(read_cursor++);
5692 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5693 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005694 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005695 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005696 }
5697 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005698 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5699 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005700 Object* new_object;
5701 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005702 return new_alloc;
5703 }
5704 StringType* new_string = StringType::cast(new_object);
5705
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005706 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005707 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005708 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005709 *(write_cursor++) = '"';
5710
5711 read_cursor = characters.start();
5712 while (read_cursor < end) {
5713 Char c = *(read_cursor++);
5714 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5715 *(write_cursor++) = c;
5716 } else {
5717 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5718 const char* replacement = JsonQuotes +
5719 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5720 for (int i = 0; i < len; i++) {
5721 *write_cursor++ = *replacement++;
5722 }
5723 }
5724 }
5725 *(write_cursor++) = '"';
5726 return new_string;
5727}
5728
5729
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005730template <typename SinkChar, typename SourceChar>
5731static inline SinkChar* WriteQuoteJsonString(
5732 Isolate* isolate,
5733 SinkChar* write_cursor,
5734 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005735 // SinkChar is only char if SourceChar is guaranteed to be char.
5736 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005737 const SourceChar* read_cursor = characters.start();
5738 const SourceChar* end = read_cursor + characters.length();
5739 *(write_cursor++) = '"';
5740 while (read_cursor < end) {
5741 SourceChar c = *(read_cursor++);
5742 if (sizeof(SourceChar) > 1u &&
5743 static_cast<unsigned>(c) >= kQuoteTableLength) {
5744 *(write_cursor++) = static_cast<SinkChar>(c);
5745 } else {
5746 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5747 const char* replacement = JsonQuotes +
5748 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5749 write_cursor[0] = replacement[0];
5750 if (len > 1) {
5751 write_cursor[1] = replacement[1];
5752 if (len > 2) {
5753 ASSERT(len == 6);
5754 write_cursor[2] = replacement[2];
5755 write_cursor[3] = replacement[3];
5756 write_cursor[4] = replacement[4];
5757 write_cursor[5] = replacement[5];
5758 }
5759 }
5760 write_cursor += len;
5761 }
5762 }
5763 *(write_cursor++) = '"';
5764 return write_cursor;
5765}
5766
5767
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005768template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005769static MaybeObject* QuoteJsonString(Isolate* isolate,
5770 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005771 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005772 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005773 int worst_case_length =
5774 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005775 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005776 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005777 }
5778
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005779 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5780 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005781 Object* new_object;
5782 if (!new_alloc->ToObject(&new_object)) {
5783 return new_alloc;
5784 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005785 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005786 // Even if our string is small enough to fit in new space we still have to
5787 // handle it being allocated in old space as may happen in the third
5788 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5789 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005790 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005791 }
5792 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005793 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005794
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005795 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005796 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005797 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005798 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5799 write_cursor,
5800 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005801 int final_length = static_cast<int>(
5802 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005803 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005804 isolate->heap()->new_space()->
5805 template ShrinkStringAtAllocationBoundary<StringType>(
5806 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005807 return new_string;
5808}
5809
5810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005811RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005812 NoHandleAllocation ha;
5813 CONVERT_CHECKED(String, str, args[0]);
5814 if (!str->IsFlat()) {
5815 MaybeObject* try_flatten = str->TryFlatten();
5816 Object* flat;
5817 if (!try_flatten->ToObject(&flat)) {
5818 return try_flatten;
5819 }
5820 str = String::cast(flat);
5821 ASSERT(str->IsFlat());
5822 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005823 String::FlatContent flat = str->GetFlatContent();
5824 ASSERT(flat.IsFlat());
5825 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005826 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005827 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005828 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005829 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005830 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005831 }
5832}
5833
5834
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005835RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005836 NoHandleAllocation ha;
5837 CONVERT_CHECKED(String, str, args[0]);
5838 if (!str->IsFlat()) {
5839 MaybeObject* try_flatten = str->TryFlatten();
5840 Object* flat;
5841 if (!try_flatten->ToObject(&flat)) {
5842 return try_flatten;
5843 }
5844 str = String::cast(flat);
5845 ASSERT(str->IsFlat());
5846 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005847 String::FlatContent flat = str->GetFlatContent();
5848 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005849 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005850 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005851 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005852 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005853 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005854 }
5855}
5856
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005857
5858template <typename Char, typename StringType>
5859static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5860 FixedArray* array,
5861 int worst_case_length) {
5862 int length = array->length();
5863
5864 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5865 worst_case_length);
5866 Object* new_object;
5867 if (!new_alloc->ToObject(&new_object)) {
5868 return new_alloc;
5869 }
5870 if (!isolate->heap()->new_space()->Contains(new_object)) {
5871 // Even if our string is small enough to fit in new space we still have to
5872 // handle it being allocated in old space as may happen in the third
5873 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5874 // CEntryStub::GenerateCore.
5875 return isolate->heap()->undefined_value();
5876 }
5877 AssertNoAllocation no_gc;
5878 StringType* new_string = StringType::cast(new_object);
5879 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5880
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005881 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005882 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005883 *(write_cursor++) = '[';
5884 for (int i = 0; i < length; i++) {
5885 if (i != 0) *(write_cursor++) = ',';
5886 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005887 String::FlatContent content = str->GetFlatContent();
5888 ASSERT(content.IsFlat());
5889 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005890 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5891 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005892 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005893 } else {
5894 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5895 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005896 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005897 }
5898 }
5899 *(write_cursor++) = ']';
5900
5901 int final_length = static_cast<int>(
5902 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005903 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005904 isolate->heap()->new_space()->
5905 template ShrinkStringAtAllocationBoundary<StringType>(
5906 new_string, final_length);
5907 return new_string;
5908}
5909
5910
5911RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5912 NoHandleAllocation ha;
5913 ASSERT(args.length() == 1);
5914 CONVERT_CHECKED(JSArray, array, args[0]);
5915
5916 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5917 FixedArray* elements = FixedArray::cast(array->elements());
5918 int n = elements->length();
5919 bool ascii = true;
5920 int total_length = 0;
5921
5922 for (int i = 0; i < n; i++) {
5923 Object* elt = elements->get(i);
5924 if (!elt->IsString()) return isolate->heap()->undefined_value();
5925 String* element = String::cast(elt);
5926 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5927 total_length += element->length();
5928 if (ascii && element->IsTwoByteRepresentation()) {
5929 ascii = false;
5930 }
5931 }
5932
5933 int worst_case_length =
5934 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5935 + total_length * kJsonQuoteWorstCaseBlowup;
5936
5937 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5938 return isolate->heap()->undefined_value();
5939 }
5940
5941 if (ascii) {
5942 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5943 elements,
5944 worst_case_length);
5945 } else {
5946 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5947 elements,
5948 worst_case_length);
5949 }
5950}
5951
5952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005953RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954 NoHandleAllocation ha;
5955
5956 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005957 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005958
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005959 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005960
lrn@chromium.org25156de2010-04-06 13:10:27 +00005961 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005962 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005963 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005964}
5965
5966
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005967RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005968 NoHandleAllocation ha;
5969 CONVERT_CHECKED(String, str, args[0]);
5970
5971 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005972 double value = StringToDouble(isolate->unicode_cache(),
5973 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974
5975 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005976 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005977}
5978
5979
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005980template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005981MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005982 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005983 String* s,
5984 int length,
5985 int input_string_length,
5986 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005987 // We try this twice, once with the assumption that the result is no longer
5988 // than the input and, if that assumption breaks, again with the exact
5989 // length. This may not be pretty, but it is nicer than what was here before
5990 // and I hereby claim my vaffel-is.
5991 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992 // Allocate the resulting string.
5993 //
5994 // NOTE: This assumes that the upper/lower case of an ascii
5995 // character is also ascii. This is currently the case, but it
5996 // might break in the future if we implement more context and locale
5997 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005998 Object* o;
5999 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000 ? isolate->heap()->AllocateRawAsciiString(length)
6001 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006002 if (!maybe_o->ToObject(&o)) return maybe_o;
6003 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006004 String* result = String::cast(o);
6005 bool has_changed_character = false;
6006
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 // Convert all characters to upper case, assuming that they will fit
6008 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006009 Access<StringInputBuffer> buffer(
6010 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006011 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006012 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006013 // We can assume that the string is not empty
6014 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006015 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006016 bool has_next = buffer->has_more();
6017 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006018 int char_length = mapping->get(current, next, chars);
6019 if (char_length == 0) {
6020 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006021 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022 i++;
6023 } else if (char_length == 1) {
6024 // Common case: converting the letter resulted in one character.
6025 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006026 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006027 has_changed_character = true;
6028 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006029 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006030 // We've assumed that the result would be as long as the
6031 // input but here is a character that converts to several
6032 // characters. No matter, we calculate the exact length
6033 // of the result and try the whole thing again.
6034 //
6035 // Note that this leaves room for optimization. We could just
6036 // memcpy what we already have to the result string. Also,
6037 // the result string is the last object allocated we could
6038 // "realloc" it and probably, in the vast majority of cases,
6039 // extend the existing string to be able to hold the full
6040 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006041 int next_length = 0;
6042 if (has_next) {
6043 next_length = mapping->get(next, 0, chars);
6044 if (next_length == 0) next_length = 1;
6045 }
6046 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006047 while (buffer->has_more()) {
6048 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006049 // NOTE: we use 0 as the next character here because, while
6050 // the next character may affect what a character converts to,
6051 // it does not in any case affect the length of what it convert
6052 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053 int char_length = mapping->get(current, 0, chars);
6054 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006055 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006056 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006057 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006058 return Failure::OutOfMemoryException();
6059 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006060 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006061 // Try again with the real length.
6062 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006063 } else {
6064 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006065 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006066 i++;
6067 }
6068 has_changed_character = true;
6069 }
6070 current = next;
6071 }
6072 if (has_changed_character) {
6073 return result;
6074 } else {
6075 // If we didn't actually change anything in doing the conversion
6076 // we simple return the result and let the converted string
6077 // become garbage; there is no reason to keep two identical strings
6078 // alive.
6079 return s;
6080 }
6081}
6082
6083
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006084namespace {
6085
lrn@chromium.org303ada72010-10-27 09:33:13 +00006086static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6087
6088
6089// Given a word and two range boundaries returns a word with high bit
6090// set in every byte iff the corresponding input byte was strictly in
6091// the range (m, n). All the other bits in the result are cleared.
6092// This function is only useful when it can be inlined and the
6093// boundaries are statically known.
6094// Requires: all bytes in the input word and the boundaries must be
6095// ascii (less than 0x7F).
6096static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6097 // Every byte in an ascii string is less than or equal to 0x7F.
6098 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6099 // Use strict inequalities since in edge cases the function could be
6100 // further simplified.
6101 ASSERT(0 < m && m < n && n < 0x7F);
6102 // Has high bit set in every w byte less than n.
6103 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6104 // Has high bit set in every w byte greater than m.
6105 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6106 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6107}
6108
6109
6110enum AsciiCaseConversion {
6111 ASCII_TO_LOWER,
6112 ASCII_TO_UPPER
6113};
6114
6115
6116template <AsciiCaseConversion dir>
6117struct FastAsciiConverter {
6118 static bool Convert(char* dst, char* src, int length) {
6119#ifdef DEBUG
6120 char* saved_dst = dst;
6121 char* saved_src = src;
6122#endif
6123 // We rely on the distance between upper and lower case letters
6124 // being a known power of 2.
6125 ASSERT('a' - 'A' == (1 << 5));
6126 // Boundaries for the range of input characters than require conversion.
6127 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6128 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6129 bool changed = false;
6130 char* const limit = src + length;
6131#ifdef V8_HOST_CAN_READ_UNALIGNED
6132 // Process the prefix of the input that requires no conversion one
6133 // (machine) word at a time.
6134 while (src <= limit - sizeof(uintptr_t)) {
6135 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6136 if (AsciiRangeMask(w, lo, hi) != 0) {
6137 changed = true;
6138 break;
6139 }
6140 *reinterpret_cast<uintptr_t*>(dst) = w;
6141 src += sizeof(uintptr_t);
6142 dst += sizeof(uintptr_t);
6143 }
6144 // Process the remainder of the input performing conversion when
6145 // required one word at a time.
6146 while (src <= limit - sizeof(uintptr_t)) {
6147 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6148 uintptr_t m = AsciiRangeMask(w, lo, hi);
6149 // The mask has high (7th) bit set in every byte that needs
6150 // conversion and we know that the distance between cases is
6151 // 1 << 5.
6152 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6153 src += sizeof(uintptr_t);
6154 dst += sizeof(uintptr_t);
6155 }
6156#endif
6157 // Process the last few bytes of the input (or the whole input if
6158 // unaligned access is not supported).
6159 while (src < limit) {
6160 char c = *src;
6161 if (lo < c && c < hi) {
6162 c ^= (1 << 5);
6163 changed = true;
6164 }
6165 *dst = c;
6166 ++src;
6167 ++dst;
6168 }
6169#ifdef DEBUG
6170 CheckConvert(saved_dst, saved_src, length, changed);
6171#endif
6172 return changed;
6173 }
6174
6175#ifdef DEBUG
6176 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6177 bool expected_changed = false;
6178 for (int i = 0; i < length; i++) {
6179 if (dst[i] == src[i]) continue;
6180 expected_changed = true;
6181 if (dir == ASCII_TO_LOWER) {
6182 ASSERT('A' <= src[i] && src[i] <= 'Z');
6183 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6184 } else {
6185 ASSERT(dir == ASCII_TO_UPPER);
6186 ASSERT('a' <= src[i] && src[i] <= 'z');
6187 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6188 }
6189 }
6190 ASSERT(expected_changed == changed);
6191 }
6192#endif
6193};
6194
6195
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006196struct ToLowerTraits {
6197 typedef unibrow::ToLowercase UnibrowConverter;
6198
lrn@chromium.org303ada72010-10-27 09:33:13 +00006199 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006200};
6201
6202
6203struct ToUpperTraits {
6204 typedef unibrow::ToUppercase UnibrowConverter;
6205
lrn@chromium.org303ada72010-10-27 09:33:13 +00006206 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006207};
6208
6209} // namespace
6210
6211
6212template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006213MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006214 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006215 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006216 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006217 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006218 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006219 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006220
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006221 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006222 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006223 if (length == 0) return s;
6224
6225 // Simpler handling of ascii strings.
6226 //
6227 // NOTE: This assumes that the upper/lower case of an ascii
6228 // character is also ascii. This is currently the case, but it
6229 // might break in the future if we implement more context and locale
6230 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006231 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006232 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006233 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006234 if (!maybe_o->ToObject(&o)) return maybe_o;
6235 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006236 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006237 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006238 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006239 return has_changed_character ? result : s;
6240 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006241
lrn@chromium.org303ada72010-10-27 09:33:13 +00006242 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006243 { MaybeObject* maybe_answer =
6244 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006245 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6246 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006247 if (answer->IsSmi()) {
6248 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006249 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006250 ConvertCaseHelper(isolate,
6251 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006252 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6253 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006254 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006255 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006256}
6257
6258
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006259RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006260 return ConvertCase<ToLowerTraits>(
6261 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262}
6263
6264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006265RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006266 return ConvertCase<ToUpperTraits>(
6267 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006268}
6269
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006270
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006271static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006272 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006273}
6274
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006275
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006276RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006277 NoHandleAllocation ha;
6278 ASSERT(args.length() == 3);
6279
6280 CONVERT_CHECKED(String, s, args[0]);
6281 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6282 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6283
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006284 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006285 int length = s->length();
6286
6287 int left = 0;
6288 if (trimLeft) {
6289 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6290 left++;
6291 }
6292 }
6293
6294 int right = length;
6295 if (trimRight) {
6296 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6297 right--;
6298 }
6299 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006300 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006301}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006302
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006303
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006304RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006305 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006306 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006307 CONVERT_ARG_CHECKED(String, subject, 0);
6308 CONVERT_ARG_CHECKED(String, pattern, 1);
6309 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6310
6311 int subject_length = subject->length();
6312 int pattern_length = pattern->length();
6313 RUNTIME_ASSERT(pattern_length > 0);
6314
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006315 if (limit == 0xffffffffu) {
6316 Handle<Object> cached_answer(StringSplitCache::Lookup(
6317 isolate->heap()->string_split_cache(),
6318 *subject,
6319 *pattern));
6320 if (*cached_answer != Smi::FromInt(0)) {
6321 Handle<JSArray> result =
6322 isolate->factory()->NewJSArrayWithElements(
6323 Handle<FixedArray>::cast(cached_answer));
6324 return *result;
6325 }
6326 }
6327
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006328 // The limit can be very large (0xffffffffu), but since the pattern
6329 // isn't empty, we can never create more parts than ~half the length
6330 // of the subject.
6331
6332 if (!subject->IsFlat()) FlattenString(subject);
6333
6334 static const int kMaxInitialListCapacity = 16;
6335
danno@chromium.org40cb8782011-05-25 07:58:50 +00006336 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006337
6338 // Find (up to limit) indices of separator and end-of-string in subject
6339 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6340 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006341 if (!pattern->IsFlat()) FlattenString(pattern);
6342
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006343 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006344
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006345 if (static_cast<uint32_t>(indices.length()) < limit) {
6346 indices.Add(subject_length);
6347 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006348
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006349 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006350
6351 // Create JSArray of substrings separated by separator.
6352 int part_count = indices.length();
6353
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006354 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006355 MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
6356 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006357 result->set_length(Smi::FromInt(part_count));
6358
6359 ASSERT(result->HasFastElements());
6360
6361 if (part_count == 1 && indices.at(0) == subject_length) {
6362 FixedArray::cast(result->elements())->set(0, *subject);
6363 return *result;
6364 }
6365
6366 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6367 int part_start = 0;
6368 for (int i = 0; i < part_count; i++) {
6369 HandleScope local_loop_handle;
6370 int part_end = indices.at(i);
6371 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006372 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006373 elements->set(i, *substring);
6374 part_start = part_end + pattern_length;
6375 }
6376
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006377 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006378 if (result->HasFastElements()) {
6379 StringSplitCache::Enter(isolate->heap(),
6380 isolate->heap()->string_split_cache(),
6381 *subject,
6382 *pattern,
6383 *elements);
6384 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006385 }
6386
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006387 return *result;
6388}
6389
6390
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006391// Copies ascii characters to the given fixed array looking up
6392// one-char strings in the cache. Gives up on the first char that is
6393// not in the cache and fills the remainder with smi zeros. Returns
6394// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006395static int CopyCachedAsciiCharsToArray(Heap* heap,
6396 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006397 FixedArray* elements,
6398 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006399 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006400 FixedArray* ascii_cache = heap->single_character_string_cache();
6401 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006402 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006403 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006404 for (i = 0; i < length; ++i) {
6405 Object* value = ascii_cache->get(chars[i]);
6406 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006407 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006408 }
6409 if (i < length) {
6410 ASSERT(Smi::FromInt(0) == 0);
6411 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6412 }
6413#ifdef DEBUG
6414 for (int j = 0; j < length; ++j) {
6415 Object* element = elements->get(j);
6416 ASSERT(element == Smi::FromInt(0) ||
6417 (element->IsString() && String::cast(element)->LooksValid()));
6418 }
6419#endif
6420 return i;
6421}
6422
6423
6424// Converts a String to JSArray.
6425// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006426RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006427 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006428 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006429 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006430 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006431
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006432 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006433 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006434
6435 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006436 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006437 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006438 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006439 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006440 { MaybeObject* maybe_obj =
6441 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006442 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6443 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006444 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006445 String::FlatContent content = s->GetFlatContent();
6446 if (content.IsAscii()) {
6447 Vector<const char> chars = content.ToAsciiVector();
6448 // Note, this will initialize all elements (not only the prefix)
6449 // to prevent GC from seeing partially initialized array.
6450 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6451 chars.start(),
6452 *elements,
6453 length);
6454 } else {
6455 MemsetPointer(elements->data_start(),
6456 isolate->heap()->undefined_value(),
6457 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006458 }
6459 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006460 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006461 }
6462 for (int i = position; i < length; ++i) {
6463 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6464 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006465 }
6466
6467#ifdef DEBUG
6468 for (int i = 0; i < length; ++i) {
6469 ASSERT(String::cast(elements->get(i))->length() == 1);
6470 }
6471#endif
6472
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006473 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006474}
6475
6476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006477RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006478 NoHandleAllocation ha;
6479 ASSERT(args.length() == 1);
6480 CONVERT_CHECKED(String, value, args[0]);
6481 return value->ToObject();
6482}
6483
6484
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006485bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006486 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006487 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006488 return char_length == 0;
6489}
6490
6491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006492RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006493 NoHandleAllocation ha;
6494 ASSERT(args.length() == 1);
6495
6496 Object* number = args[0];
6497 RUNTIME_ASSERT(number->IsNumber());
6498
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006499 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006500}
6501
6502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006503RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006504 NoHandleAllocation ha;
6505 ASSERT(args.length() == 1);
6506
6507 Object* number = args[0];
6508 RUNTIME_ASSERT(number->IsNumber());
6509
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006510 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006511}
6512
6513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006514RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515 NoHandleAllocation ha;
6516 ASSERT(args.length() == 1);
6517
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006518 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006519
6520 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6521 if (number > 0 && number <= Smi::kMaxValue) {
6522 return Smi::FromInt(static_cast<int>(number));
6523 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006524 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525}
6526
6527
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006528RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006529 NoHandleAllocation ha;
6530 ASSERT(args.length() == 1);
6531
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006532 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006533
6534 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6535 if (number > 0 && number <= Smi::kMaxValue) {
6536 return Smi::FromInt(static_cast<int>(number));
6537 }
6538
6539 double double_value = DoubleToInteger(number);
6540 // Map both -0 and +0 to +0.
6541 if (double_value == 0) double_value = 0;
6542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006543 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006544}
6545
6546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006547RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006548 NoHandleAllocation ha;
6549 ASSERT(args.length() == 1);
6550
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006551 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006552 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006553}
6554
6555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006556RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006557 NoHandleAllocation ha;
6558 ASSERT(args.length() == 1);
6559
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006560 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006561
6562 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6563 if (number > 0 && number <= Smi::kMaxValue) {
6564 return Smi::FromInt(static_cast<int>(number));
6565 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006566 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006567}
6568
6569
ager@chromium.org870a0b62008-11-04 11:43:05 +00006570// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6571// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006572RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006573 NoHandleAllocation ha;
6574 ASSERT(args.length() == 1);
6575
6576 Object* obj = args[0];
6577 if (obj->IsSmi()) {
6578 return obj;
6579 }
6580 if (obj->IsHeapNumber()) {
6581 double value = HeapNumber::cast(obj)->value();
6582 int int_value = FastD2I(value);
6583 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6584 return Smi::FromInt(int_value);
6585 }
6586 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006587 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006588}
6589
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006591RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006592 NoHandleAllocation ha;
6593 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006594 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006595}
6596
6597
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006598RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006599 NoHandleAllocation ha;
6600 ASSERT(args.length() == 2);
6601
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006602 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6603 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006604 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006605}
6606
6607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006608RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609 NoHandleAllocation ha;
6610 ASSERT(args.length() == 2);
6611
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006612 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6613 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006614 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006615}
6616
6617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006618RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619 NoHandleAllocation ha;
6620 ASSERT(args.length() == 2);
6621
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006622 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6623 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006625}
6626
6627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006628RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006629 NoHandleAllocation ha;
6630 ASSERT(args.length() == 1);
6631
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006632 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006633 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634}
6635
6636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006637RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006638 NoHandleAllocation ha;
6639 ASSERT(args.length() == 0);
6640
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006641 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006642}
6643
6644
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006645RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646 NoHandleAllocation ha;
6647 ASSERT(args.length() == 2);
6648
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006649 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6650 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006651 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652}
6653
6654
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006655RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006656 NoHandleAllocation ha;
6657 ASSERT(args.length() == 2);
6658
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006659 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6660 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661
ager@chromium.org3811b432009-10-28 14:53:37 +00006662 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006663 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006664 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006665}
6666
6667
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006668RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006669 NoHandleAllocation ha;
6670 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671 CONVERT_CHECKED(String, str1, args[0]);
6672 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006673 isolate->counters()->string_add_runtime()->Increment();
6674 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006675}
6676
6677
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006678template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006679static inline void StringBuilderConcatHelper(String* special,
6680 sinkchar* sink,
6681 FixedArray* fixed_array,
6682 int array_length) {
6683 int position = 0;
6684 for (int i = 0; i < array_length; i++) {
6685 Object* element = fixed_array->get(i);
6686 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006687 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006688 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006689 int pos;
6690 int len;
6691 if (encoded_slice > 0) {
6692 // Position and length encoded in one smi.
6693 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6694 len = StringBuilderSubstringLength::decode(encoded_slice);
6695 } else {
6696 // Position and length encoded in two smis.
6697 Object* obj = fixed_array->get(++i);
6698 ASSERT(obj->IsSmi());
6699 pos = Smi::cast(obj)->value();
6700 len = -encoded_slice;
6701 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006702 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006703 sink + position,
6704 pos,
6705 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006706 position += len;
6707 } else {
6708 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006709 int element_length = string->length();
6710 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006711 position += element_length;
6712 }
6713 }
6714}
6715
6716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006717RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006718 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006719 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006720 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006721 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006722 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006723 return Failure::OutOfMemoryException();
6724 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006725 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006726 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006727
6728 // This assumption is used by the slice encoding in one or two smis.
6729 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6730
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006731 MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
6732 if (maybe_result->IsFailure()) return maybe_result;
6733
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006734 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006736 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 }
6738 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006739 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006741 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006742
6743 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006745 } else if (array_length == 1) {
6746 Object* first = fixed_array->get(0);
6747 if (first->IsString()) return first;
6748 }
6749
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006750 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006751 int position = 0;
6752 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006753 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006754 Object* elt = fixed_array->get(i);
6755 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006756 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006757 int smi_value = Smi::cast(elt)->value();
6758 int pos;
6759 int len;
6760 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006761 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006762 pos = StringBuilderSubstringPosition::decode(smi_value);
6763 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006764 } else {
6765 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006766 len = -smi_value;
6767 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006768 i++;
6769 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006770 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006771 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006772 Object* next_smi = fixed_array->get(i);
6773 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006774 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006775 }
6776 pos = Smi::cast(next_smi)->value();
6777 if (pos < 0) {
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 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006780 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006781 ASSERT(pos >= 0);
6782 ASSERT(len >= 0);
6783 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006784 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006785 }
6786 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006787 } else if (elt->IsString()) {
6788 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006789 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006790 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006791 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006792 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006793 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006795 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006797 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006798 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006799 return Failure::OutOfMemoryException();
6800 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006801 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006802 }
6803
6804 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006805 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006806
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006808 { MaybeObject* maybe_object =
6809 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006810 if (!maybe_object->ToObject(&object)) return maybe_object;
6811 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006812 SeqAsciiString* answer = SeqAsciiString::cast(object);
6813 StringBuilderConcatHelper(special,
6814 answer->GetChars(),
6815 fixed_array,
6816 array_length);
6817 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006818 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006819 { MaybeObject* maybe_object =
6820 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006821 if (!maybe_object->ToObject(&object)) return maybe_object;
6822 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006823 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6824 StringBuilderConcatHelper(special,
6825 answer->GetChars(),
6826 fixed_array,
6827 array_length);
6828 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006829 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006830}
6831
6832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006833RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006834 NoHandleAllocation ha;
6835 ASSERT(args.length() == 3);
6836 CONVERT_CHECKED(JSArray, array, args[0]);
6837 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006838 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006839 return Failure::OutOfMemoryException();
6840 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006841 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006842 CONVERT_CHECKED(String, separator, args[2]);
6843
6844 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006845 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006846 }
6847 FixedArray* fixed_array = FixedArray::cast(array->elements());
6848 if (fixed_array->length() < array_length) {
6849 array_length = fixed_array->length();
6850 }
6851
6852 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006853 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006854 } else if (array_length == 1) {
6855 Object* first = fixed_array->get(0);
6856 if (first->IsString()) return first;
6857 }
6858
6859 int separator_length = separator->length();
6860 int max_nof_separators =
6861 (String::kMaxLength + separator_length - 1) / separator_length;
6862 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006863 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006864 return Failure::OutOfMemoryException();
6865 }
6866 int length = (array_length - 1) * separator_length;
6867 for (int i = 0; i < array_length; i++) {
6868 Object* element_obj = fixed_array->get(i);
6869 if (!element_obj->IsString()) {
6870 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006871 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006872 }
6873 String* element = String::cast(element_obj);
6874 int increment = element->length();
6875 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006876 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006877 return Failure::OutOfMemoryException();
6878 }
6879 length += increment;
6880 }
6881
6882 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006883 { MaybeObject* maybe_object =
6884 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006885 if (!maybe_object->ToObject(&object)) return maybe_object;
6886 }
6887 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6888
6889 uc16* sink = answer->GetChars();
6890#ifdef DEBUG
6891 uc16* end = sink + length;
6892#endif
6893
6894 String* first = String::cast(fixed_array->get(0));
6895 int first_length = first->length();
6896 String::WriteToFlat(first, sink, 0, first_length);
6897 sink += first_length;
6898
6899 for (int i = 1; i < array_length; i++) {
6900 ASSERT(sink + separator_length <= end);
6901 String::WriteToFlat(separator, sink, 0, separator_length);
6902 sink += separator_length;
6903
6904 String* element = String::cast(fixed_array->get(i));
6905 int element_length = element->length();
6906 ASSERT(sink + element_length <= end);
6907 String::WriteToFlat(element, sink, 0, element_length);
6908 sink += element_length;
6909 }
6910 ASSERT(sink == end);
6911
6912 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6913 return answer;
6914}
6915
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006916template <typename Char>
6917static void JoinSparseArrayWithSeparator(FixedArray* elements,
6918 int elements_length,
6919 uint32_t array_length,
6920 String* separator,
6921 Vector<Char> buffer) {
6922 int previous_separator_position = 0;
6923 int separator_length = separator->length();
6924 int cursor = 0;
6925 for (int i = 0; i < elements_length; i += 2) {
6926 int position = NumberToInt32(elements->get(i));
6927 String* string = String::cast(elements->get(i + 1));
6928 int string_length = string->length();
6929 if (string->length() > 0) {
6930 while (previous_separator_position < position) {
6931 String::WriteToFlat<Char>(separator, &buffer[cursor],
6932 0, separator_length);
6933 cursor += separator_length;
6934 previous_separator_position++;
6935 }
6936 String::WriteToFlat<Char>(string, &buffer[cursor],
6937 0, string_length);
6938 cursor += string->length();
6939 }
6940 }
6941 if (separator_length > 0) {
6942 // Array length must be representable as a signed 32-bit number,
6943 // otherwise the total string length would have been too large.
6944 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6945 int last_array_index = static_cast<int>(array_length - 1);
6946 while (previous_separator_position < last_array_index) {
6947 String::WriteToFlat<Char>(separator, &buffer[cursor],
6948 0, separator_length);
6949 cursor += separator_length;
6950 previous_separator_position++;
6951 }
6952 }
6953 ASSERT(cursor <= buffer.length());
6954}
6955
6956
6957RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6958 NoHandleAllocation ha;
6959 ASSERT(args.length() == 3);
6960 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006961 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6962 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006963 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6964 CONVERT_CHECKED(String, separator, args[2]);
6965 // elements_array is fast-mode JSarray of alternating positions
6966 // (increasing order) and strings.
6967 // array_length is length of original array (used to add separators);
6968 // separator is string to put between elements. Assumed to be non-empty.
6969
6970 // Find total length of join result.
6971 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006972 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006973 int max_string_length;
6974 if (is_ascii) {
6975 max_string_length = SeqAsciiString::kMaxLength;
6976 } else {
6977 max_string_length = SeqTwoByteString::kMaxLength;
6978 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006979 bool overflow = false;
6980 CONVERT_NUMBER_CHECKED(int, elements_length,
6981 Int32, elements_array->length());
6982 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6983 FixedArray* elements = FixedArray::cast(elements_array->elements());
6984 for (int i = 0; i < elements_length; i += 2) {
6985 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6986 CONVERT_CHECKED(String, string, elements->get(i + 1));
6987 int length = string->length();
6988 if (is_ascii && !string->IsAsciiRepresentation()) {
6989 is_ascii = false;
6990 max_string_length = SeqTwoByteString::kMaxLength;
6991 }
6992 if (length > max_string_length ||
6993 max_string_length - length < string_length) {
6994 overflow = true;
6995 break;
6996 }
6997 string_length += length;
6998 }
6999 int separator_length = separator->length();
7000 if (!overflow && separator_length > 0) {
7001 if (array_length <= 0x7fffffffu) {
7002 int separator_count = static_cast<int>(array_length) - 1;
7003 int remaining_length = max_string_length - string_length;
7004 if ((remaining_length / separator_length) >= separator_count) {
7005 string_length += separator_length * (array_length - 1);
7006 } else {
7007 // Not room for the separators within the maximal string length.
7008 overflow = true;
7009 }
7010 } else {
7011 // Nonempty separator and at least 2^31-1 separators necessary
7012 // means that the string is too large to create.
7013 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7014 overflow = true;
7015 }
7016 }
7017 if (overflow) {
7018 // Throw OutOfMemory exception for creating too large a string.
7019 V8::FatalProcessOutOfMemory("Array join result too large.");
7020 }
7021
7022 if (is_ascii) {
7023 MaybeObject* result_allocation =
7024 isolate->heap()->AllocateRawAsciiString(string_length);
7025 if (result_allocation->IsFailure()) return result_allocation;
7026 SeqAsciiString* result_string =
7027 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7028 JoinSparseArrayWithSeparator<char>(elements,
7029 elements_length,
7030 array_length,
7031 separator,
7032 Vector<char>(result_string->GetChars(),
7033 string_length));
7034 return result_string;
7035 } else {
7036 MaybeObject* result_allocation =
7037 isolate->heap()->AllocateRawTwoByteString(string_length);
7038 if (result_allocation->IsFailure()) return result_allocation;
7039 SeqTwoByteString* result_string =
7040 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7041 JoinSparseArrayWithSeparator<uc16>(elements,
7042 elements_length,
7043 array_length,
7044 separator,
7045 Vector<uc16>(result_string->GetChars(),
7046 string_length));
7047 return result_string;
7048 }
7049}
7050
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007051
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007052RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053 NoHandleAllocation ha;
7054 ASSERT(args.length() == 2);
7055
7056 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7057 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007058 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007059}
7060
7061
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007062RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007063 NoHandleAllocation ha;
7064 ASSERT(args.length() == 2);
7065
7066 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7067 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007068 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007069}
7070
7071
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007072RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007073 NoHandleAllocation ha;
7074 ASSERT(args.length() == 2);
7075
7076 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7077 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007078 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007079}
7080
7081
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007082RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007083 NoHandleAllocation ha;
7084 ASSERT(args.length() == 1);
7085
7086 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007087 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007088}
7089
7090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007091RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007092 NoHandleAllocation ha;
7093 ASSERT(args.length() == 2);
7094
7095 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7096 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007097 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098}
7099
7100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007101RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007102 NoHandleAllocation ha;
7103 ASSERT(args.length() == 2);
7104
7105 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7106 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007107 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007108}
7109
7110
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007111RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007112 NoHandleAllocation ha;
7113 ASSERT(args.length() == 2);
7114
7115 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7116 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007117 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007118}
7119
7120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007121RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007122 NoHandleAllocation ha;
7123 ASSERT(args.length() == 2);
7124
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007125 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7126 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007127 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7128 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7129 if (x == y) return Smi::FromInt(EQUAL);
7130 Object* result;
7131 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7132 result = Smi::FromInt(EQUAL);
7133 } else {
7134 result = Smi::FromInt(NOT_EQUAL);
7135 }
7136 return result;
7137}
7138
7139
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007140RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007141 NoHandleAllocation ha;
7142 ASSERT(args.length() == 2);
7143
7144 CONVERT_CHECKED(String, x, args[0]);
7145 CONVERT_CHECKED(String, y, args[1]);
7146
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007147 bool not_equal = !x->Equals(y);
7148 // This is slightly convoluted because the value that signifies
7149 // equality is 0 and inequality is 1 so we have to negate the result
7150 // from String::Equals.
7151 ASSERT(not_equal == 0 || not_equal == 1);
7152 STATIC_CHECK(EQUAL == 0);
7153 STATIC_CHECK(NOT_EQUAL == 1);
7154 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007155}
7156
7157
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007158RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007159 NoHandleAllocation ha;
7160 ASSERT(args.length() == 3);
7161
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007162 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7163 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007164 if (isnan(x) || isnan(y)) return args[2];
7165 if (x == y) return Smi::FromInt(EQUAL);
7166 if (isless(x, y)) return Smi::FromInt(LESS);
7167 return Smi::FromInt(GREATER);
7168}
7169
7170
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007171// Compare two Smis as if they were converted to strings and then
7172// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007173RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007174 NoHandleAllocation ha;
7175 ASSERT(args.length() == 2);
7176
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007177 // Extract the integer values from the Smis.
7178 CONVERT_CHECKED(Smi, x, args[0]);
7179 CONVERT_CHECKED(Smi, y, args[1]);
7180 int x_value = x->value();
7181 int y_value = y->value();
7182
7183 // If the integers are equal so are the string representations.
7184 if (x_value == y_value) return Smi::FromInt(EQUAL);
7185
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007186 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007187 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007188 if (x_value == 0 || y_value == 0)
7189 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007190
ager@chromium.org32912102009-01-16 10:38:43 +00007191 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007192 // smallest because the char code of '-' is less than the char code
7193 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007194
7195 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7196 // architectures using 32-bit Smis.
7197 uint32_t x_scaled = x_value;
7198 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007199 if (x_value < 0 || y_value < 0) {
7200 if (y_value >= 0) return Smi::FromInt(LESS);
7201 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007202 x_scaled = -x_value;
7203 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007204 }
7205
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007206 static const uint32_t kPowersOf10[] = {
7207 1, 10, 100, 1000, 10*1000, 100*1000,
7208 1000*1000, 10*1000*1000, 100*1000*1000,
7209 1000*1000*1000
7210 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007211
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007212 // If the integers have the same number of decimal digits they can be
7213 // compared directly as the numeric order is the same as the
7214 // lexicographic order. If one integer has fewer digits, it is scaled
7215 // by some power of 10 to have the same number of digits as the longer
7216 // integer. If the scaled integers are equal it means the shorter
7217 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007218
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007219 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7220 int x_log2 = IntegerLog2(x_scaled);
7221 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7222 x_log10 -= x_scaled < kPowersOf10[x_log10];
7223
7224 int y_log2 = IntegerLog2(y_scaled);
7225 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7226 y_log10 -= y_scaled < kPowersOf10[y_log10];
7227
7228 int tie = EQUAL;
7229
7230 if (x_log10 < y_log10) {
7231 // X has fewer digits. We would like to simply scale up X but that
7232 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7233 // be scaled up to 9_000_000_000. So we scale up by the next
7234 // smallest power and scale down Y to drop one digit. It is OK to
7235 // drop one digit from the longer integer since the final digit is
7236 // past the length of the shorter integer.
7237 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7238 y_scaled /= 10;
7239 tie = LESS;
7240 } else if (y_log10 < x_log10) {
7241 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7242 x_scaled /= 10;
7243 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007244 }
7245
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007246 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7247 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7248 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007249}
7250
7251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007252static Object* StringInputBufferCompare(RuntimeState* state,
7253 String* x,
7254 String* y) {
7255 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7256 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007257 bufx.Reset(x);
7258 bufy.Reset(y);
7259 while (bufx.has_more() && bufy.has_more()) {
7260 int d = bufx.GetNext() - bufy.GetNext();
7261 if (d < 0) return Smi::FromInt(LESS);
7262 else if (d > 0) return Smi::FromInt(GREATER);
7263 }
7264
7265 // x is (non-trivial) prefix of y:
7266 if (bufy.has_more()) return Smi::FromInt(LESS);
7267 // y is prefix of x:
7268 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7269}
7270
7271
7272static Object* FlatStringCompare(String* x, String* y) {
7273 ASSERT(x->IsFlat());
7274 ASSERT(y->IsFlat());
7275 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7276 int prefix_length = x->length();
7277 if (y->length() < prefix_length) {
7278 prefix_length = y->length();
7279 equal_prefix_result = Smi::FromInt(GREATER);
7280 } else if (y->length() > prefix_length) {
7281 equal_prefix_result = Smi::FromInt(LESS);
7282 }
7283 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007284 String::FlatContent x_content = x->GetFlatContent();
7285 String::FlatContent y_content = y->GetFlatContent();
7286 if (x_content.IsAscii()) {
7287 Vector<const char> x_chars = x_content.ToAsciiVector();
7288 if (y_content.IsAscii()) {
7289 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007290 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007291 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007292 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007293 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7294 }
7295 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007296 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7297 if (y_content.IsAscii()) {
7298 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007299 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7300 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007301 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007302 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7303 }
7304 }
7305 Object* result;
7306 if (r == 0) {
7307 result = equal_prefix_result;
7308 } else {
7309 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7310 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007311 ASSERT(result ==
7312 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007313 return result;
7314}
7315
7316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007317RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007318 NoHandleAllocation ha;
7319 ASSERT(args.length() == 2);
7320
7321 CONVERT_CHECKED(String, x, args[0]);
7322 CONVERT_CHECKED(String, y, args[1]);
7323
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007324 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007325
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007326 // A few fast case tests before we flatten.
7327 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007328 if (y->length() == 0) {
7329 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007330 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007331 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007332 return Smi::FromInt(LESS);
7333 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007334
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007335 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007336 if (d < 0) return Smi::FromInt(LESS);
7337 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007338
lrn@chromium.org303ada72010-10-27 09:33:13 +00007339 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007340 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007341 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7342 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007343 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007344 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7345 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007346
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007347 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007348 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007349}
7350
7351
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007352RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007353 NoHandleAllocation ha;
7354 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007355 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007356
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007357 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007358 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007359}
7360
7361
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007362RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007363 NoHandleAllocation ha;
7364 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007365 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007366
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007367 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007368 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007369}
7370
7371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007372RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007373 NoHandleAllocation ha;
7374 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007375 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007376
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007377 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007378 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007379}
7380
7381
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007382static const double kPiDividedBy4 = 0.78539816339744830962;
7383
7384
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007385RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007386 NoHandleAllocation ha;
7387 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007388 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007389
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007390 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7391 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007392 double result;
7393 if (isinf(x) && isinf(y)) {
7394 // Make sure that the result in case of two infinite arguments
7395 // is a multiple of Pi / 4. The sign of the result is determined
7396 // by the first argument (x) and the sign of the second argument
7397 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007398 int multiplier = (x < 0) ? -1 : 1;
7399 if (y < 0) multiplier *= 3;
7400 result = multiplier * kPiDividedBy4;
7401 } else {
7402 result = atan2(x, y);
7403 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007404 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007405}
7406
7407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007408RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007409 NoHandleAllocation ha;
7410 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007411 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007412
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007413 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007414 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007415}
7416
7417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007418RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007419 NoHandleAllocation ha;
7420 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007421 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007422
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007423 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007424 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007425}
7426
7427
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007428RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007429 NoHandleAllocation ha;
7430 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007431 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007432
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007433 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007434 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007435}
7436
7437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007438RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007439 NoHandleAllocation ha;
7440 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007441 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007442
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007443 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007444 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007445}
7446
7447
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007448RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007449 NoHandleAllocation ha;
7450 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007451 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007452
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007453 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007454 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007455}
7456
7457
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007458RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007459 NoHandleAllocation ha;
7460 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007461 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007462
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007463 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007464
7465 // If the second argument is a smi, it is much faster to call the
7466 // custom powi() function than the generic pow().
7467 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007468 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007469 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007470 }
7471
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007472 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007473 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007474}
7475
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007476// Fast version of Math.pow if we know that y is not an integer and
7477// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007478RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007479 NoHandleAllocation ha;
7480 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007481 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7482 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007483 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007484 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007485 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007486 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007487 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007488 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007489 }
7490}
7491
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007492
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007493RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007494 NoHandleAllocation ha;
7495 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007496 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007497
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007498 if (!args[0]->IsHeapNumber()) {
7499 // Must be smi. Return the argument unchanged for all the other types
7500 // to make fuzz-natives test happy.
7501 return args[0];
7502 }
7503
7504 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7505
7506 double value = number->value();
7507 int exponent = number->get_exponent();
7508 int sign = number->get_sign();
7509
danno@chromium.org160a7b02011-04-18 15:51:38 +00007510 if (exponent < -1) {
7511 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7512 if (sign) return isolate->heap()->minus_zero_value();
7513 return Smi::FromInt(0);
7514 }
7515
7516 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7517 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7518 // agument holds for 32-bit smis).
7519 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007520 return Smi::FromInt(static_cast<int>(value + 0.5));
7521 }
7522
7523 // If the magnitude is big enough, there's no place for fraction part. If we
7524 // try to add 0.5 to this number, 1.0 will be added instead.
7525 if (exponent >= 52) {
7526 return number;
7527 }
7528
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007529 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007530
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007531 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007532 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007533}
7534
7535
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007536RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007537 NoHandleAllocation ha;
7538 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007539 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007540
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007541 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007542 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007543}
7544
7545
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007546RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007547 NoHandleAllocation ha;
7548 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007549 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007550
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007551 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007552 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007553}
7554
7555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007556RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007557 NoHandleAllocation ha;
7558 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007559 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007560
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007561 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007562 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007563}
7564
7565
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007566static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007567 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7568 181, 212, 243, 273, 304, 334};
7569 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7570 182, 213, 244, 274, 305, 335};
7571
7572 year += month / 12;
7573 month %= 12;
7574 if (month < 0) {
7575 year--;
7576 month += 12;
7577 }
7578
7579 ASSERT(month >= 0);
7580 ASSERT(month < 12);
7581
7582 // year_delta is an arbitrary number such that:
7583 // a) year_delta = -1 (mod 400)
7584 // b) year + year_delta > 0 for years in the range defined by
7585 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7586 // Jan 1 1970. This is required so that we don't run into integer
7587 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007588 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007589 // operations.
7590 static const int year_delta = 399999;
7591 static const int base_day = 365 * (1970 + year_delta) +
7592 (1970 + year_delta) / 4 -
7593 (1970 + year_delta) / 100 +
7594 (1970 + year_delta) / 400;
7595
7596 int year1 = year + year_delta;
7597 int day_from_year = 365 * year1 +
7598 year1 / 4 -
7599 year1 / 100 +
7600 year1 / 400 -
7601 base_day;
7602
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007603 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7604 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007605 }
7606
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007607 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007608}
7609
7610
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007611RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007612 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007613 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007614
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007615 CONVERT_SMI_ARG_CHECKED(year, 0);
7616 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007617
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007618 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007619}
7620
7621
7622static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7623static const int kDaysIn4Years = 4 * 365 + 1;
7624static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7625static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7626static const int kDays1970to2000 = 30 * 365 + 7;
7627static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7628 kDays1970to2000;
7629static const int kYearsOffset = 400000;
7630
7631static const char kDayInYear[] = {
7632 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7633 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7634 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7635 22, 23, 24, 25, 26, 27, 28,
7636 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7637 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7638 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7639 22, 23, 24, 25, 26, 27, 28, 29, 30,
7640 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7641 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7642 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7643 22, 23, 24, 25, 26, 27, 28, 29, 30,
7644 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7645 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7646 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7647 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7648 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7649 22, 23, 24, 25, 26, 27, 28, 29, 30,
7650 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7651 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7652 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7653 22, 23, 24, 25, 26, 27, 28, 29, 30,
7654 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7655 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7656
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, 29, 30, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
7673 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7674 22, 23, 24, 25, 26, 27, 28, 29, 30,
7675 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7676 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7677 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7678 22, 23, 24, 25, 26, 27, 28, 29, 30,
7679 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7680 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7681
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, 29, 30, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
7698 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7699 22, 23, 24, 25, 26, 27, 28, 29, 30,
7700 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7701 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7702 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7703 22, 23, 24, 25, 26, 27, 28, 29, 30,
7704 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7705 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7706
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, 30, 31,
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,
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, 31,
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,
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, 31,
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,
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, 31,
7723 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7724 22, 23, 24, 25, 26, 27, 28, 29, 30,
7725 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7726 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7727 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7728 22, 23, 24, 25, 26, 27, 28, 29, 30,
7729 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7730 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7731
7732static const char kMonthInYear[] = {
7733 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,
7734 0, 0, 0, 0, 0, 0,
7735 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,
7736 1, 1, 1,
7737 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,
7738 2, 2, 2, 2, 2, 2,
7739 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,
7740 3, 3, 3, 3, 3,
7741 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,
7742 4, 4, 4, 4, 4, 4,
7743 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,
7744 5, 5, 5, 5, 5,
7745 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,
7746 6, 6, 6, 6, 6, 6,
7747 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,
7748 7, 7, 7, 7, 7, 7,
7749 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,
7750 8, 8, 8, 8, 8,
7751 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,
7752 9, 9, 9, 9, 9, 9,
7753 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7754 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7755 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7756 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7757
7758 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,
7759 0, 0, 0, 0, 0, 0,
7760 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,
7761 1, 1, 1,
7762 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,
7763 2, 2, 2, 2, 2, 2,
7764 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,
7765 3, 3, 3, 3, 3,
7766 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,
7767 4, 4, 4, 4, 4, 4,
7768 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,
7769 5, 5, 5, 5, 5,
7770 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,
7771 6, 6, 6, 6, 6, 6,
7772 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,
7773 7, 7, 7, 7, 7, 7,
7774 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,
7775 8, 8, 8, 8, 8,
7776 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,
7777 9, 9, 9, 9, 9, 9,
7778 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7779 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7780 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7781 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7782
7783 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,
7784 0, 0, 0, 0, 0, 0,
7785 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,
7786 1, 1, 1, 1,
7787 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,
7788 2, 2, 2, 2, 2, 2,
7789 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,
7790 3, 3, 3, 3, 3,
7791 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,
7792 4, 4, 4, 4, 4, 4,
7793 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,
7794 5, 5, 5, 5, 5,
7795 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,
7796 6, 6, 6, 6, 6, 6,
7797 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,
7798 7, 7, 7, 7, 7, 7,
7799 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,
7800 8, 8, 8, 8, 8,
7801 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,
7802 9, 9, 9, 9, 9, 9,
7803 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7804 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7805 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7806 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7807
7808 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,
7809 0, 0, 0, 0, 0, 0,
7810 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,
7811 1, 1, 1,
7812 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,
7813 2, 2, 2, 2, 2, 2,
7814 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,
7815 3, 3, 3, 3, 3,
7816 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,
7817 4, 4, 4, 4, 4, 4,
7818 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,
7819 5, 5, 5, 5, 5,
7820 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,
7821 6, 6, 6, 6, 6, 6,
7822 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,
7823 7, 7, 7, 7, 7, 7,
7824 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,
7825 8, 8, 8, 8, 8,
7826 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,
7827 9, 9, 9, 9, 9, 9,
7828 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7829 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7830 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7831 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7832
7833
7834// This function works for dates from 1970 to 2099.
7835static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007836 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007837#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007838 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007839#endif
7840
7841 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7842 date %= kDaysIn4Years;
7843
7844 month = kMonthInYear[date];
7845 day = kDayInYear[date];
7846
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007847 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007848}
7849
7850
7851static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007852 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007853#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007854 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007855#endif
7856
7857 date += kDaysOffset;
7858 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7859 date %= kDaysIn400Years;
7860
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007861 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007862
7863 date--;
7864 int yd1 = date / kDaysIn100Years;
7865 date %= kDaysIn100Years;
7866 year += 100 * yd1;
7867
7868 date++;
7869 int yd2 = date / kDaysIn4Years;
7870 date %= kDaysIn4Years;
7871 year += 4 * yd2;
7872
7873 date--;
7874 int yd3 = date / 365;
7875 date %= 365;
7876 year += yd3;
7877
7878 bool is_leap = (!yd1 || yd2) && !yd3;
7879
7880 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007881 ASSERT(is_leap || (date >= 0));
7882 ASSERT((date < 365) || (is_leap && (date < 366)));
7883 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007884 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7885 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007886
7887 if (is_leap) {
7888 day = kDayInYear[2*365 + 1 + date];
7889 month = kMonthInYear[2*365 + 1 + date];
7890 } else {
7891 day = kDayInYear[date];
7892 month = kMonthInYear[date];
7893 }
7894
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007895 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007896}
7897
7898
7899static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007900 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007901 if (date >= 0 && date < 32 * kDaysIn4Years) {
7902 DateYMDFromTimeAfter1970(date, year, month, day);
7903 } else {
7904 DateYMDFromTimeSlow(date, year, month, day);
7905 }
7906}
7907
7908
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007909RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007910 NoHandleAllocation ha;
7911 ASSERT(args.length() == 2);
7912
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007913 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007914 CONVERT_CHECKED(JSArray, res_array, args[1]);
7915
7916 int year, month, day;
7917 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7918
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007919 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7920 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007921 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007922
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007923 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7924 if (maybe->IsFailure()) return maybe;
7925 FixedArray* elms = FixedArray::cast(res_array->elements());
7926 elms->set(0, Smi::FromInt(year));
7927 elms->set(1, Smi::FromInt(month));
7928 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007929
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007930 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007931}
7932
7933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007934RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007935 HandleScope scope(isolate);
7936 ASSERT(args.length() == 3);
7937
7938 Handle<JSFunction> callee = args.at<JSFunction>(0);
7939 Object** parameters = reinterpret_cast<Object**>(args[1]);
7940 const int argument_count = Smi::cast(args[2])->value();
7941
7942 Handle<JSObject> result =
7943 isolate->factory()->NewArgumentsObject(callee, argument_count);
7944 // Allocate the elements if needed.
7945 int parameter_count = callee->shared()->formal_parameter_count();
7946 if (argument_count > 0) {
7947 if (parameter_count > 0) {
7948 int mapped_count = Min(argument_count, parameter_count);
7949 Handle<FixedArray> parameter_map =
7950 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7951 parameter_map->set_map(
7952 isolate->heap()->non_strict_arguments_elements_map());
7953
7954 Handle<Map> old_map(result->map());
7955 Handle<Map> new_map =
7956 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007957 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007958
7959 result->set_map(*new_map);
7960 result->set_elements(*parameter_map);
7961
7962 // Store the context and the arguments array at the beginning of the
7963 // parameter map.
7964 Handle<Context> context(isolate->context());
7965 Handle<FixedArray> arguments =
7966 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7967 parameter_map->set(0, *context);
7968 parameter_map->set(1, *arguments);
7969
7970 // Loop over the actual parameters backwards.
7971 int index = argument_count - 1;
7972 while (index >= mapped_count) {
7973 // These go directly in the arguments array and have no
7974 // corresponding slot in the parameter map.
7975 arguments->set(index, *(parameters - index - 1));
7976 --index;
7977 }
7978
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007979 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007980 while (index >= 0) {
7981 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007982 Handle<String> name(scope_info->ParameterName(index));
7983 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007984 bool duplicate = false;
7985 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007986 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007987 duplicate = true;
7988 break;
7989 }
7990 }
7991
7992 if (duplicate) {
7993 // This goes directly in the arguments array with a hole in the
7994 // parameter map.
7995 arguments->set(index, *(parameters - index - 1));
7996 parameter_map->set_the_hole(index + 2);
7997 } else {
7998 // The context index goes in the parameter map with a hole in the
7999 // arguments array.
8000 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008001 for (int j = 0; j < context_local_count; ++j) {
8002 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008003 context_index = j;
8004 break;
8005 }
8006 }
8007 ASSERT(context_index >= 0);
8008 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008009 parameter_map->set(index + 2, Smi::FromInt(
8010 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00008011 }
8012
8013 --index;
8014 }
8015 } else {
8016 // If there is no aliasing, the arguments object elements are not
8017 // special in any way.
8018 Handle<FixedArray> elements =
8019 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8020 result->set_elements(*elements);
8021 for (int i = 0; i < argument_count; ++i) {
8022 elements->set(i, *(parameters - i - 1));
8023 }
8024 }
8025 }
8026 return *result;
8027}
8028
8029
8030RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008031 NoHandleAllocation ha;
8032 ASSERT(args.length() == 3);
8033
8034 JSFunction* callee = JSFunction::cast(args[0]);
8035 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008036 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008037
lrn@chromium.org303ada72010-10-27 09:33:13 +00008038 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008039 { MaybeObject* maybe_result =
8040 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008041 if (!maybe_result->ToObject(&result)) return maybe_result;
8042 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008043 // Allocate the elements if needed.
8044 if (length > 0) {
8045 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008046 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008047 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008048 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8049 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008050
8051 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008052 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008053 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008054 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008055
8056 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008057 for (int i = 0; i < length; i++) {
8058 array->set(i, *--parameters, mode);
8059 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008060 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008061 }
8062 return result;
8063}
8064
8065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008066RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008067 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008068 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008069 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008070 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008071 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072
whesse@chromium.org7b260152011-06-20 15:33:18 +00008073 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008074 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008075 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008076 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008077 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8078 context,
8079 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008080 return *result;
8081}
8082
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008083
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008084// Find the arguments of the JavaScript function invocation that called
8085// into C++ code. Collect these in a newly allocated array of handles (possibly
8086// prefixed by a number of empty handles).
8087static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8088 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008089 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008090 // Find frame containing arguments passed to the caller.
8091 JavaScriptFrameIterator it;
8092 JavaScriptFrame* frame = it.frame();
8093 List<JSFunction*> functions(2);
8094 frame->GetFunctions(&functions);
8095 if (functions.length() > 1) {
8096 int inlined_frame_index = functions.length() - 1;
8097 JSFunction* inlined_function = functions[inlined_frame_index];
8098 int args_count = inlined_function->shared()->formal_parameter_count();
8099 ScopedVector<SlotRef> args_slots(args_count);
8100 SlotRef::ComputeSlotMappingForArguments(frame,
8101 inlined_frame_index,
8102 &args_slots);
8103
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008104 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008105 SmartArrayPointer<Handle<Object> > param_data(
8106 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008107 for (int i = 0; i < args_count; i++) {
8108 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008109 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008110 }
8111 return param_data;
8112 } else {
8113 it.AdvanceToArgumentsFrame();
8114 frame = it.frame();
8115 int args_count = frame->ComputeParametersCount();
8116
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008117 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008118 SmartArrayPointer<Handle<Object> > param_data(
8119 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008120 for (int i = 0; i < args_count; i++) {
8121 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008122 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008123 }
8124 return param_data;
8125 }
8126}
8127
8128
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008129RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8130 HandleScope scope(isolate);
8131 ASSERT(args.length() == 4);
8132 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8133 RUNTIME_ASSERT(args[3]->IsNumber());
8134 Handle<Object> bindee = args.at<Object>(1);
8135
8136 // TODO(lrn): Create bound function in C++ code from premade shared info.
8137 bound_function->shared()->set_bound(true);
8138 // Get all arguments of calling function (Function.prototype.bind).
8139 int argc = 0;
8140 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8141 // Don't count the this-arg.
8142 if (argc > 0) {
8143 ASSERT(*arguments[0] == args[2]);
8144 argc--;
8145 } else {
8146 ASSERT(args[2]->IsUndefined());
8147 }
8148 // Initialize array of bindings (function, this, and any existing arguments
8149 // if the function was already bound).
8150 Handle<FixedArray> new_bindings;
8151 int i;
8152 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8153 Handle<FixedArray> old_bindings(
8154 JSFunction::cast(*bindee)->function_bindings());
8155 new_bindings =
8156 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8157 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8158 i = 0;
8159 for (int n = old_bindings->length(); i < n; i++) {
8160 new_bindings->set(i, old_bindings->get(i));
8161 }
8162 } else {
8163 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8164 new_bindings = isolate->factory()->NewFixedArray(array_size);
8165 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8166 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8167 i = 2;
8168 }
8169 // Copy arguments, skipping the first which is "this_arg".
8170 for (int j = 0; j < argc; j++, i++) {
8171 new_bindings->set(i, *arguments[j + 1]);
8172 }
8173 new_bindings->set_map(isolate->heap()->fixed_cow_array_map());
8174 bound_function->set_function_bindings(*new_bindings);
8175
8176 // Update length.
8177 Handle<String> length_symbol = isolate->factory()->length_symbol();
8178 Handle<Object> new_length(args.at<Object>(3));
8179 PropertyAttributes attr =
8180 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8181 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8182 return *bound_function;
8183}
8184
8185
8186RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8187 HandleScope handles(isolate);
8188 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008189 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008190 if (callable->IsJSFunction()) {
8191 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8192 if (function->shared()->bound()) {
8193 Handle<FixedArray> bindings(function->function_bindings());
8194 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8195 return *isolate->factory()->NewJSArrayWithElements(bindings);
8196 }
8197 }
8198 return isolate->heap()->undefined_value();
8199}
8200
8201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008202RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008203 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008204 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008205 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008206 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008207 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008208
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008209 // The argument is a bound function. Extract its bound arguments
8210 // and callable.
8211 Handle<FixedArray> bound_args =
8212 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8213 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8214 Handle<Object> bound_function(
8215 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8216 ASSERT(!bound_function->IsJSFunction() ||
8217 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008219 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008220 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008221 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008222 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008223 param_data[i] = Handle<Object>(bound_args->get(
8224 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008225 }
8226
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008227 if (!bound_function->IsJSFunction()) {
8228 bool exception_thrown;
8229 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8230 &exception_thrown);
8231 if (exception_thrown) return Failure::Exception();
8232 }
8233 ASSERT(bound_function->IsJSFunction());
8234
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008235 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008236 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008237 Execution::New(Handle<JSFunction>::cast(bound_function),
8238 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008239 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008240 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008241 }
8242 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008243 return *result;
8244}
8245
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008246
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008247static void TrySettingInlineConstructStub(Isolate* isolate,
8248 Handle<JSFunction> function) {
8249 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008250 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008251 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008252 }
8253 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008254 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008255 Handle<Code> code = compiler.CompileConstructStub(function);
8256 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008257 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008258}
8259
8260
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008261RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008262 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008263 ASSERT(args.length() == 1);
8264
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008265 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008266
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008267 // If the constructor isn't a proper function we throw a type error.
8268 if (!constructor->IsJSFunction()) {
8269 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8270 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008271 isolate->factory()->NewTypeError("not_constructor", arguments);
8272 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008273 }
8274
8275 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008276
8277 // If function should not have prototype, construction is not allowed. In this
8278 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008279 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008280 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8281 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282 isolate->factory()->NewTypeError("not_constructor", arguments);
8283 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008284 }
8285
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008286#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008287 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008288 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008289 if (debug->StepInActive()) {
8290 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008291 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008292#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008293
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008294 if (function->has_initial_map()) {
8295 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008296 // The 'Function' function ignores the receiver object when
8297 // called using 'new' and creates a new JSFunction object that
8298 // is returned. The receiver object is only used for error
8299 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008300 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008301 // allocate JSFunctions since it does not properly initialize
8302 // the shared part of the function. Since the receiver is
8303 // ignored anyway, we use the global object as the receiver
8304 // instead of a new JSFunction object. This way, errors are
8305 // reported the same way whether or not 'Function' is called
8306 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008307 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008308 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008309 }
8310
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008311 // The function should be compiled for the optimization hints to be
8312 // available. We cannot use EnsureCompiled because that forces a
8313 // compilation through the shared function info which makes it
8314 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008315 if (!function->is_compiled()) {
8316 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8317 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008318
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008319 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008320 if (!function->has_initial_map() &&
8321 shared->IsInobjectSlackTrackingInProgress()) {
8322 // The tracking is already in progress for another function. We can only
8323 // track one initial_map at a time, so we force the completion before the
8324 // function is called as a constructor for the first time.
8325 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008326 }
8327
8328 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008329 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8330 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008331 // Delay setting the stub if inobject slack tracking is in progress.
8332 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008333 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008334 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008335
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008336 isolate->counters()->constructed_objects()->Increment();
8337 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008338
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008339 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008340}
8341
8342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008343RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008344 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008345 ASSERT(args.length() == 1);
8346
8347 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8348 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008349 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008351 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008352}
8353
8354
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008355RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008356 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008357 ASSERT(args.length() == 1);
8358
8359 Handle<JSFunction> function = args.at<JSFunction>(0);
8360#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008361 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008362 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008363 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008364 PrintF("]\n");
8365 }
8366#endif
8367
lrn@chromium.org34e60782011-09-15 07:25:40 +00008368 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008369 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008370 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008371 return Failure::Exception();
8372 }
8373
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008374 // All done. Return the compiled code.
8375 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008376 return function->code();
8377}
8378
8379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008380RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008381 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008382 ASSERT(args.length() == 1);
8383 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008384
8385 // If the function is not compiled ignore the lazy
8386 // recompilation. This can happen if the debugger is activated and
8387 // the function is returned to the not compiled state.
8388 if (!function->shared()->is_compiled()) {
8389 function->ReplaceCode(function->shared()->code());
8390 return function->code();
8391 }
8392
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008393 // If the function is not optimizable or debugger is active continue using the
8394 // code from the full compiler.
8395 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008396 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008397 if (FLAG_trace_opt) {
8398 PrintF("[failed to optimize ");
8399 function->PrintName();
8400 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8401 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008402 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008403 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008404 function->ReplaceCode(function->shared()->code());
8405 return function->code();
8406 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008407 if (JSFunction::CompileOptimized(function,
8408 AstNode::kNoNumber,
8409 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008410 return function->code();
8411 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008412 if (FLAG_trace_opt) {
8413 PrintF("[failed to optimize ");
8414 function->PrintName();
8415 PrintF(": optimized compilation failed]\n");
8416 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008417 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008418 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008419}
8420
8421
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008422class ActivationsFinder : public ThreadVisitor {
8423 public:
8424 explicit ActivationsFinder(JSFunction* function)
8425 : function_(function), has_activations_(false) {}
8426
8427 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8428 if (has_activations_) return;
8429
8430 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8431 JavaScriptFrame* frame = it.frame();
8432 if (frame->is_optimized() && frame->function() == function_) {
8433 has_activations_ = true;
8434 return;
8435 }
8436 }
8437 }
8438
8439 bool has_activations() { return has_activations_; }
8440
8441 private:
8442 JSFunction* function_;
8443 bool has_activations_;
8444};
8445
8446
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008447RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008448 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008449 ASSERT(args.length() == 1);
8450 RUNTIME_ASSERT(args[0]->IsSmi());
8451 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008452 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008453 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8454 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008455 int frames = deoptimizer->output_count();
8456
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008457 deoptimizer->MaterializeHeapNumbers();
8458 delete deoptimizer;
8459
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008460 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008461 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008462 for (int i = 0; i < frames - 1; i++) it.Advance();
8463 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008464
8465 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008466 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008467 Handle<Object> arguments;
8468 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008469 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008470 if (arguments.is_null()) {
8471 // FunctionGetArguments can't throw an exception, so cast away the
8472 // doubt with an assert.
8473 arguments = Handle<Object>(
8474 Accessors::FunctionGetArguments(*function,
8475 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008476 ASSERT(*arguments != isolate->heap()->null_value());
8477 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008478 }
8479 frame->SetExpression(i, *arguments);
8480 }
8481 }
8482
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008483 if (type == Deoptimizer::EAGER) {
8484 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008485 }
8486
8487 // Avoid doing too much work when running with --always-opt and keep
8488 // the optimized code around.
8489 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008491 }
8492
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008493 // Find other optimized activations of the function.
8494 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008495 while (!it.done()) {
8496 JavaScriptFrame* frame = it.frame();
8497 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008498 has_other_activations = true;
8499 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008500 }
8501 it.Advance();
8502 }
8503
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008504 if (!has_other_activations) {
8505 ActivationsFinder activations_finder(*function);
8506 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8507 has_other_activations = activations_finder.has_activations();
8508 }
8509
8510 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008511 if (FLAG_trace_deopt) {
8512 PrintF("[removing optimized code for: ");
8513 function->PrintName();
8514 PrintF("]\n");
8515 }
8516 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008517 } else {
8518 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008519 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008520 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008521}
8522
8523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008524RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008525 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008526 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008527 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008528}
8529
8530
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008531RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008532 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008533 ASSERT(args.length() == 1);
8534 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008535 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008536
8537 Deoptimizer::DeoptimizeFunction(*function);
8538
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008539 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008540}
8541
8542
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008543RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8544#if defined(USE_SIMULATOR)
8545 return isolate->heap()->true_value();
8546#else
8547 return isolate->heap()->false_value();
8548#endif
8549}
8550
8551
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008552RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8553 HandleScope scope(isolate);
8554 ASSERT(args.length() == 1);
8555 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8556 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8557 function->MarkForLazyRecompilation();
8558 return isolate->heap()->undefined_value();
8559}
8560
8561
lrn@chromium.org1c092762011-05-09 09:42:16 +00008562RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8563 HandleScope scope(isolate);
8564 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008565 // The least significant bit (after untagging) indicates whether the
8566 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008567 if (!V8::UseCrankshaft()) {
8568 return Smi::FromInt(4); // 4 == "never".
8569 }
8570 if (FLAG_always_opt) {
8571 return Smi::FromInt(3); // 3 == "always".
8572 }
8573 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8574 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8575 : Smi::FromInt(2); // 2 == "no".
8576}
8577
8578
8579RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8580 HandleScope scope(isolate);
8581 ASSERT(args.length() == 1);
8582 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8583 return Smi::FromInt(function->shared()->opt_count());
8584}
8585
8586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008587RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008588 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008589 ASSERT(args.length() == 1);
8590 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8591
8592 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008593 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008594
8595 // We have hit a back edge in an unoptimized frame for a function that was
8596 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008597 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008598 // Keep track of whether we've succeeded in optimizing.
8599 bool succeeded = unoptimized->optimizable();
8600 if (succeeded) {
8601 // If we are trying to do OSR when there are already optimized
8602 // activations of the function, it means (a) the function is directly or
8603 // indirectly recursive and (b) an optimized invocation has been
8604 // deoptimized so that we are currently in an unoptimized activation.
8605 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008606 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008607 while (succeeded && !it.done()) {
8608 JavaScriptFrame* frame = it.frame();
8609 succeeded = !frame->is_optimized() || frame->function() != *function;
8610 it.Advance();
8611 }
8612 }
8613
8614 int ast_id = AstNode::kNoNumber;
8615 if (succeeded) {
8616 // The top JS function is this one, the PC is somewhere in the
8617 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008618 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008619 JavaScriptFrame* frame = it.frame();
8620 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008621 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008622 ASSERT(unoptimized->contains(frame->pc()));
8623
8624 // Use linear search of the unoptimized code's stack check table to find
8625 // the AST id matching the PC.
8626 Address start = unoptimized->instruction_start();
8627 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008628 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008629 uint32_t table_length = Memory::uint32_at(table_cursor);
8630 table_cursor += kIntSize;
8631 for (unsigned i = 0; i < table_length; ++i) {
8632 // Table entries are (AST id, pc offset) pairs.
8633 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8634 if (pc_offset == target_pc_offset) {
8635 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8636 break;
8637 }
8638 table_cursor += 2 * kIntSize;
8639 }
8640 ASSERT(ast_id != AstNode::kNoNumber);
8641 if (FLAG_trace_osr) {
8642 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8643 function->PrintName();
8644 PrintF("]\n");
8645 }
8646
8647 // Try to compile the optimized code. A true return value from
8648 // CompileOptimized means that compilation succeeded, not necessarily
8649 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008650 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008651 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008652 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8653 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008654 if (data->OsrPcOffset()->value() >= 0) {
8655 if (FLAG_trace_osr) {
8656 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008657 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008658 }
8659 ASSERT(data->OsrAstId()->value() == ast_id);
8660 } else {
8661 // We may never generate the desired OSR entry if we emit an
8662 // early deoptimize.
8663 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008664 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008665 } else {
8666 succeeded = false;
8667 }
8668 }
8669
8670 // Revert to the original stack checks in the original unoptimized code.
8671 if (FLAG_trace_osr) {
8672 PrintF("[restoring original stack checks in ");
8673 function->PrintName();
8674 PrintF("]\n");
8675 }
8676 StackCheckStub check_stub;
8677 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008678 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008679 Deoptimizer::RevertStackCheckCode(*unoptimized,
8680 *check_code,
8681 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008682
8683 // Allow OSR only at nesting level zero again.
8684 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8685
8686 // If the optimization attempt succeeded, return the AST id tagged as a
8687 // smi. This tells the builtin that we need to translate the unoptimized
8688 // frame to an optimized one.
8689 if (succeeded) {
8690 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8691 return Smi::FromInt(ast_id);
8692 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008693 if (function->IsMarkedForLazyRecompilation()) {
8694 function->ReplaceCode(function->shared()->code());
8695 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008696 return Smi::FromInt(-1);
8697 }
8698}
8699
8700
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008701RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8702 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8703 return isolate->heap()->undefined_value();
8704}
8705
8706
danno@chromium.orgc612e022011-11-10 11:38:15 +00008707RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8708 HandleScope scope(isolate);
8709 ASSERT(args.length() >= 2);
8710 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8711 Object* receiver = args[0];
8712 int argc = args.length() - 2;
8713
8714 // If there are too many arguments, allocate argv via malloc.
8715 const int argv_small_size = 10;
8716 Handle<Object> argv_small_buffer[argv_small_size];
8717 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8718 Handle<Object>* argv = argv_small_buffer;
8719 if (argc > argv_small_size) {
8720 argv = new Handle<Object>[argc];
8721 if (argv == NULL) return isolate->StackOverflow();
8722 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8723 }
8724
8725 for (int i = 0; i < argc; ++i) {
8726 MaybeObject* maybe = args[1 + i];
8727 Object* object;
8728 if (!maybe->To<Object>(&object)) return maybe;
8729 argv[i] = Handle<Object>(object);
8730 }
8731
8732 bool threw;
8733 Handle<JSReceiver> hfun(fun);
8734 Handle<Object> hreceiver(receiver);
8735 Handle<Object> result =
8736 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8737
8738 if (threw) return Failure::Exception();
8739 return *result;
8740}
8741
8742
lrn@chromium.org34e60782011-09-15 07:25:40 +00008743RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8744 HandleScope scope(isolate);
8745 ASSERT(args.length() == 5);
8746 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8747 Object* receiver = args[1];
8748 CONVERT_CHECKED(JSObject, arguments, args[2]);
8749 CONVERT_CHECKED(Smi, shift, args[3]);
8750 CONVERT_CHECKED(Smi, arity, args[4]);
8751
8752 int offset = shift->value();
8753 int argc = arity->value();
8754 ASSERT(offset >= 0);
8755 ASSERT(argc >= 0);
8756
8757 // If there are too many arguments, allocate argv via malloc.
8758 const int argv_small_size = 10;
8759 Handle<Object> argv_small_buffer[argv_small_size];
8760 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8761 Handle<Object>* argv = argv_small_buffer;
8762 if (argc > argv_small_size) {
8763 argv = new Handle<Object>[argc];
8764 if (argv == NULL) return isolate->StackOverflow();
8765 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8766 }
8767
8768 for (int i = 0; i < argc; ++i) {
8769 MaybeObject* maybe = arguments->GetElement(offset + i);
8770 Object* object;
8771 if (!maybe->To<Object>(&object)) return maybe;
8772 argv[i] = Handle<Object>(object);
8773 }
8774
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008775 bool threw;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008776 Handle<JSReceiver> hfun(fun);
8777 Handle<Object> hreceiver(receiver);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008778 Handle<Object> result =
8779 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008780
8781 if (threw) return Failure::Exception();
8782 return *result;
8783}
8784
8785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008786RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008787 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008788 ASSERT(args.length() == 1);
8789 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8790 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8791}
8792
8793
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008794RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008795 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008796 ASSERT(args.length() == 1);
8797 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8798 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8799}
8800
8801
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008802RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008803 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008804 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008805
kasper.lund7276f142008-07-30 08:49:36 +00008806 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008807 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008808 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008809 { MaybeObject* maybe_result =
8810 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008811 if (!maybe_result->ToObject(&result)) return maybe_result;
8812 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008813
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008814 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008815
kasper.lund7276f142008-07-30 08:49:36 +00008816 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008817}
8818
lrn@chromium.org303ada72010-10-27 09:33:13 +00008819
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008820RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8821 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008822 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008823 JSObject* extension_object;
8824 if (args[0]->IsJSObject()) {
8825 extension_object = JSObject::cast(args[0]);
8826 } else {
8827 // Convert the object to a proper JavaScript object.
8828 MaybeObject* maybe_js_object = args[0]->ToObject();
8829 if (!maybe_js_object->To(&extension_object)) {
8830 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8831 HandleScope scope(isolate);
8832 Handle<Object> handle = args.at<Object>(0);
8833 Handle<Object> result =
8834 isolate->factory()->NewTypeError("with_expression",
8835 HandleVector(&handle, 1));
8836 return isolate->Throw(*result);
8837 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008838 return maybe_js_object;
8839 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008840 }
8841 }
8842
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008843 JSFunction* function;
8844 if (args[1]->IsSmi()) {
8845 // A smi sentinel indicates a context nested inside global code rather
8846 // than some function. There is a canonical empty function that can be
8847 // gotten from the global context.
8848 function = isolate->context()->global_context()->closure();
8849 } else {
8850 function = JSFunction::cast(args[1]);
8851 }
8852
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008853 Context* context;
8854 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008855 isolate->heap()->AllocateWithContext(function,
8856 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008857 extension_object);
8858 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008859 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008860 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008861}
8862
8863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008864RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008865 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008866 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008867 String* name = String::cast(args[0]);
8868 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008869 JSFunction* function;
8870 if (args[2]->IsSmi()) {
8871 // A smi sentinel indicates a context nested inside global code rather
8872 // than some function. There is a canonical empty function that can be
8873 // gotten from the global context.
8874 function = isolate->context()->global_context()->closure();
8875 } else {
8876 function = JSFunction::cast(args[2]);
8877 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008878 Context* context;
8879 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008880 isolate->heap()->AllocateCatchContext(function,
8881 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008882 name,
8883 thrown_object);
8884 if (!maybe_context->To(&context)) return maybe_context;
8885 isolate->set_context(context);
8886 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008887}
8888
8889
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008890RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8891 NoHandleAllocation ha;
8892 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008893 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008894 JSFunction* function;
8895 if (args[1]->IsSmi()) {
8896 // A smi sentinel indicates a context nested inside global code rather
8897 // than some function. There is a canonical empty function that can be
8898 // gotten from the global context.
8899 function = isolate->context()->global_context()->closure();
8900 } else {
8901 function = JSFunction::cast(args[1]);
8902 }
8903 Context* context;
8904 MaybeObject* maybe_context =
8905 isolate->heap()->AllocateBlockContext(function,
8906 isolate->context(),
8907 scope_info);
8908 if (!maybe_context->To(&context)) return maybe_context;
8909 isolate->set_context(context);
8910 return context;
8911}
8912
8913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008914RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008915 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008916 ASSERT(args.length() == 2);
8917
8918 CONVERT_ARG_CHECKED(Context, context, 0);
8919 CONVERT_ARG_CHECKED(String, name, 1);
8920
8921 int index;
8922 PropertyAttributes attributes;
8923 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008924 BindingFlags binding_flags;
8925 Handle<Object> holder = context->Lookup(name,
8926 flags,
8927 &index,
8928 &attributes,
8929 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008930
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008931 // If the slot was not found the result is true.
8932 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008933 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008934 }
8935
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008936 // If the slot was found in a context, it should be DONT_DELETE.
8937 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008938 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008939 }
8940
8941 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008942 // the global object, or the subject of a with. Try to delete it
8943 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008944 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008945 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008946}
8947
8948
ager@chromium.orga1645e22009-09-09 19:27:10 +00008949// A mechanism to return a pair of Object pointers in registers (if possible).
8950// How this is achieved is calling convention-dependent.
8951// All currently supported x86 compiles uses calling conventions that are cdecl
8952// variants where a 64-bit value is returned in two 32-bit registers
8953// (edx:eax on ia32, r1:r0 on ARM).
8954// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8955// In Win64 calling convention, a struct of two pointers is returned in memory,
8956// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008957#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008958struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008959 MaybeObject* x;
8960 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008961};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008962
lrn@chromium.org303ada72010-10-27 09:33:13 +00008963static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008964 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008965 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8966 // In Win64 they are assigned to a hidden first argument.
8967 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008968}
8969#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008970typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008971static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008972 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008973 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008974}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008975#endif
8976
8977
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008978static inline MaybeObject* Unhole(Heap* heap,
8979 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008980 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8982 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008983 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008984}
8985
8986
danno@chromium.org40cb8782011-05-25 07:58:50 +00008987static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8988 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008989 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008990 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008991 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008992 JSFunction* context_extension_function =
8993 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008994 // If the holder isn't a context extension object, we just return it
8995 // as the receiver. This allows arguments objects to be used as
8996 // receivers, but only if they are put in the context scope chain
8997 // explicitly via a with-statement.
8998 Object* constructor = holder->map()->constructor();
8999 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00009000 // Fall back to using the global object as the implicit receiver if
9001 // the property turns out to be a local variable allocated in a
9002 // context extension object - introduced via eval. Implicit global
9003 // receivers are indicated with the hole value.
9004 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009005}
9006
9007
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009008static ObjectPair LoadContextSlotHelper(Arguments args,
9009 Isolate* isolate,
9010 bool throw_error) {
9011 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009012 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009013
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009014 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009015 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009016 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009017 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009018 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019
9020 int index;
9021 PropertyAttributes attributes;
9022 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009023 BindingFlags binding_flags;
9024 Handle<Object> holder = context->Lookup(name,
9025 flags,
9026 &index,
9027 &attributes,
9028 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009029
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009030 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009032 ASSERT(holder->IsContext());
9033 // If the "property" we were looking for is a local variable, the
9034 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009035 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009036 // Use the hole as the receiver to signal that the receiver is implicit
9037 // and that the global receiver should be used (as distinguished from an
9038 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009039 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009040 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009041 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009042 switch (binding_flags) {
9043 case MUTABLE_CHECK_INITIALIZED:
9044 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9045 if (value->IsTheHole()) {
9046 Handle<Object> reference_error =
9047 isolate->factory()->NewReferenceError("not_defined",
9048 HandleVector(&name, 1));
9049 return MakePair(isolate->Throw(*reference_error), NULL);
9050 }
9051 // FALLTHROUGH
9052 case MUTABLE_IS_INITIALIZED:
9053 case IMMUTABLE_IS_INITIALIZED:
9054 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9055 ASSERT(!value->IsTheHole());
9056 return MakePair(value, *receiver);
9057 case IMMUTABLE_CHECK_INITIALIZED:
9058 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9059 case MISSING_BINDING:
9060 UNREACHABLE();
9061 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009062 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009063 }
9064
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009065 // Otherwise, if the slot was found the holder is a context extension
9066 // object, subject of a with, or a global object. We read the named
9067 // property from it.
9068 if (!holder.is_null()) {
9069 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9070 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009071 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009072 Handle<Object> receiver_handle(object->IsGlobalObject()
9073 ? GlobalObject::cast(*object)->global_receiver()
9074 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009075
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009076 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009077 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009078 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009079 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009080 }
9081
9082 if (throw_error) {
9083 // The property doesn't exist - throw exception.
9084 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009085 isolate->factory()->NewReferenceError("not_defined",
9086 HandleVector(&name, 1));
9087 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009088 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009089 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009090 return MakePair(isolate->heap()->undefined_value(),
9091 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009092 }
9093}
9094
9095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009096RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009097 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098}
9099
9100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009101RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009102 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009103}
9104
9105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009106RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009107 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009108 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009110 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009111 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009112 CONVERT_ARG_CHECKED(String, name, 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009113 CONVERT_STRICT_MODE_ARG(strict_mode, 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009114
9115 int index;
9116 PropertyAttributes attributes;
9117 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009118 BindingFlags binding_flags;
9119 Handle<Object> holder = context->Lookup(name,
9120 flags,
9121 &index,
9122 &attributes,
9123 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009124
9125 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009126 // The property was found in a context slot.
9127 Handle<Context> context = Handle<Context>::cast(holder);
9128 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9129 context->get(index)->IsTheHole()) {
9130 Handle<Object> error =
9131 isolate->factory()->NewReferenceError("not_defined",
9132 HandleVector(&name, 1));
9133 return isolate->Throw(*error);
9134 }
9135 // Ignore if read_only variable.
9136 if ((attributes & READ_ONLY) == 0) {
9137 // Context is a fixed array and set cannot fail.
9138 context->set(index, *value);
9139 } else if (strict_mode == kStrictMode) {
9140 // Setting read only property in strict mode.
9141 Handle<Object> error =
9142 isolate->factory()->NewTypeError("strict_cannot_assign",
9143 HandleVector(&name, 1));
9144 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009145 }
9146 return *value;
9147 }
9148
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009149 // Slow case: The property is not in a context slot. It is either in a
9150 // context extension object, a property of the subject of a with, or a
9151 // property of the global object.
9152 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009153
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009154 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009155 // The property exists on the holder.
9156 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009157 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009158 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009160
9161 if (strict_mode == kStrictMode) {
9162 // Throw in strict mode (assignment to undefined variable).
9163 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009164 isolate->factory()->NewReferenceError(
9165 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009166 return isolate->Throw(*error);
9167 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009168 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009169 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009170 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171 }
9172
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009173 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009174 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009175 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009176 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009177 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009178 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009179 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009180 // Setting read only property in strict mode.
9181 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009182 isolate->factory()->NewTypeError(
9183 "strict_cannot_assign", HandleVector(&name, 1));
9184 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009185 }
9186 return *value;
9187}
9188
9189
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009190RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009191 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009192 ASSERT(args.length() == 1);
9193
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009194 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009195}
9196
9197
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009198RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009199 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009200 ASSERT(args.length() == 1);
9201
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009202 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009203}
9204
9205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009206RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009207 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009208 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009209}
9210
9211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009212RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009213 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009214 ASSERT(args.length() == 1);
9215
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009216 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009217 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009218 isolate->factory()->NewReferenceError("not_defined",
9219 HandleVector(&name, 1));
9220 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009221}
9222
9223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009224RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009225 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009226
9227 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009228 if (isolate->stack_guard()->IsStackOverflow()) {
9229 NoHandleAllocation na;
9230 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009231 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009232
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009233 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234}
9235
9236
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009237static int StackSize() {
9238 int n = 0;
9239 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9240 return n;
9241}
9242
9243
9244static void PrintTransition(Object* result) {
9245 // indentation
9246 { const int nmax = 80;
9247 int n = StackSize();
9248 if (n <= nmax)
9249 PrintF("%4d:%*s", n, n, "");
9250 else
9251 PrintF("%4d:%*s", n, nmax, "...");
9252 }
9253
9254 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009255 JavaScriptFrame::PrintTop(stdout, true, false);
9256 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009257 } else {
9258 // function result
9259 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009260 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009261 PrintF("\n");
9262 }
9263}
9264
9265
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009266RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
9267 ASSERT(args.length() == 5);
9268 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9269 CONVERT_SMI_ARG_CHECKED(from_kind, 1);
9270 CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
9271 CONVERT_SMI_ARG_CHECKED(to_kind, 3);
9272 CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
9273 NoHandleAllocation ha;
9274 PrintF("*");
9275 obj->PrintElementsTransition(stdout,
9276 static_cast<ElementsKind>(from_kind), *from_elements,
9277 static_cast<ElementsKind>(to_kind), *to_elements);
9278 return isolate->heap()->undefined_value();
9279}
9280
9281
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009282RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009283 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009284 NoHandleAllocation ha;
9285 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009286 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009287}
9288
9289
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009290RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009291 NoHandleAllocation ha;
9292 PrintTransition(args[0]);
9293 return args[0]; // return TOS
9294}
9295
9296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009297RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009298 NoHandleAllocation ha;
9299 ASSERT(args.length() == 1);
9300
9301#ifdef DEBUG
9302 if (args[0]->IsString()) {
9303 // If we have a string, assume it's a code "marker"
9304 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009305 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009306 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009307 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9308 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009309 } else {
9310 PrintF("DebugPrint: ");
9311 }
9312 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009313 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009314 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009315 HeapObject::cast(args[0])->map()->Print();
9316 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009317#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009318 // ShortPrint is available in release mode. Print is not.
9319 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009320#endif
9321 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009322 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009323
9324 return args[0]; // return TOS
9325}
9326
9327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009328RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009329 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009330 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009331 isolate->PrintStack();
9332 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009333}
9334
9335
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009336RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009337 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009338 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009339
9340 // According to ECMA-262, section 15.9.1, page 117, the precision of
9341 // the number in a Date object representing a particular instant in
9342 // time is milliseconds. Therefore, we floor the result of getting
9343 // the OS time.
9344 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009345 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009346}
9347
9348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009349RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009350 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009351 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009352
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009353 CONVERT_ARG_CHECKED(String, str, 0);
9354 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009355
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009356 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009357
9358 MaybeObject* maybe_result_array =
9359 output->EnsureCanContainNonSmiElements();
9360 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009361 RUNTIME_ASSERT(output->HasFastElements());
9362
9363 AssertNoAllocation no_allocation;
9364
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009365 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009366 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9367 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009368 String::FlatContent str_content = str->GetFlatContent();
9369 if (str_content.IsAscii()) {
9370 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009371 output_array,
9372 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009373 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009374 ASSERT(str_content.IsTwoByte());
9375 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009376 output_array,
9377 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009378 }
9379
9380 if (result) {
9381 return *output;
9382 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009383 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009384 }
9385}
9386
9387
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009388RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009389 NoHandleAllocation ha;
9390 ASSERT(args.length() == 1);
9391
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009392 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009393 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009394 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009395}
9396
9397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009398RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009399 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009400 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009402 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009403}
9404
9405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009406RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009407 NoHandleAllocation ha;
9408 ASSERT(args.length() == 1);
9409
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009410 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009411 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009412}
9413
9414
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009415RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009416 ASSERT(args.length() == 1);
9417 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009418 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009419 return JSGlobalObject::cast(global)->global_receiver();
9420}
9421
9422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009423RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009424 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009425 ASSERT_EQ(1, args.length());
9426 CONVERT_ARG_CHECKED(String, source, 0);
9427
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009428 source = Handle<String>(source->TryFlattenGetString());
9429 // Optimized fast case where we only have ascii characters.
9430 Handle<Object> result;
9431 if (source->IsSeqAsciiString()) {
9432 result = JsonParser<true>::Parse(source);
9433 } else {
9434 result = JsonParser<false>::Parse(source);
9435 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009436 if (result.is_null()) {
9437 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009438 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009439 return Failure::Exception();
9440 }
9441 return *result;
9442}
9443
9444
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009445bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9446 Handle<Context> context) {
9447 if (context->allow_code_gen_from_strings()->IsFalse()) {
9448 // Check with callback if set.
9449 AllowCodeGenerationFromStringsCallback callback =
9450 isolate->allow_code_gen_callback();
9451 if (callback == NULL) {
9452 // No callback set and code generation disallowed.
9453 return false;
9454 } else {
9455 // Callback set. Let it decide if code generation is allowed.
9456 VMState state(isolate, EXTERNAL);
9457 return callback(v8::Utils::ToLocal(context));
9458 }
9459 }
9460 return true;
9461}
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.
9474 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9475 return isolate->Throw(*isolate->factory()->NewError(
9476 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9477 }
9478
9479 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009480 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9481 source, context, true, kNonStrictMode, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009482 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009483 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009484 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9485 context,
9486 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009487 return *fun;
9488}
9489
9490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009491static ObjectPair CompileGlobalEval(Isolate* isolate,
9492 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009493 Handle<Object> receiver,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009494 StrictModeFlag strict_mode,
9495 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009496 Handle<Context> context = Handle<Context>(isolate->context());
9497 Handle<Context> global_context = Handle<Context>(context->global_context());
9498
9499 // Check if global context allows code generation from
9500 // strings. Throw an exception if it doesn't.
9501 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9502 isolate->Throw(*isolate->factory()->NewError(
9503 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9504 return MakePair(Failure::Exception(), NULL);
9505 }
9506
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009507 // Deal with a normal eval call with a string argument. Compile it
9508 // and return the compiled function bound in the local context.
9509 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9510 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009511 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009512 context->IsGlobalContext(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009513 strict_mode,
9514 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009515 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009516 Handle<JSFunction> compiled =
9517 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009518 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009519 return MakePair(*compiled, *receiver);
9520}
9521
9522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009523RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009524 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009525
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009526 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009527 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009528
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009529 // If "eval" didn't refer to the original GlobalEval, it's not a
9530 // direct call to eval.
9531 // (And even if it is, but the first argument isn't a string, just let
9532 // execution default to an indirect call to eval, which will also return
9533 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009534 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009535 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009536 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009537 }
9538
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009539 CONVERT_STRICT_MODE_ARG(strict_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009540 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009541 return CompileGlobalEval(isolate,
9542 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009543 args.at<Object>(2),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009544 strict_mode,
9545 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009546}
9547
9548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009549RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009550 // This utility adjusts the property attributes for newly created Function
9551 // object ("new Function(...)") by changing the map.
9552 // All it does is changing the prototype property to enumerable
9553 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009554 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009555 ASSERT(args.length() == 1);
9556 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009557
9558 Handle<Map> map = func->shared()->strict_mode()
9559 ? isolate->strict_mode_function_instance_map()
9560 : isolate->function_instance_map();
9561
9562 ASSERT(func->map()->instance_type() == map->instance_type());
9563 ASSERT(func->map()->instance_size() == map->instance_size());
9564 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009565 return *func;
9566}
9567
9568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009569RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009570 // Allocate a block of memory in NewSpace (filled with a filler).
9571 // Use as fallback for allocation in generated code when NewSpace
9572 // is full.
9573 ASSERT(args.length() == 1);
9574 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9575 int size = size_smi->value();
9576 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9577 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009578 Heap* heap = isolate->heap();
9579 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009580 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009581 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009582 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009583 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009584 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009585 }
9586 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009587 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009588}
9589
9590
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009591// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009592// array. Returns true if the element was pushed on the stack and
9593// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009594RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009595 ASSERT(args.length() == 2);
9596 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009597 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009598 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009599 int length = Smi::cast(array->length())->value();
9600 FixedArray* elements = FixedArray::cast(array->elements());
9601 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009602 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009603 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009604 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009605 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009606 { MaybeObject* maybe_obj =
9607 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009608 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9609 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009610 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009611}
9612
9613
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009614/**
9615 * A simple visitor visits every element of Array's.
9616 * The backend storage can be a fixed array for fast elements case,
9617 * or a dictionary for sparse array. Since Dictionary is a subtype
9618 * of FixedArray, the class can be used by both fast and slow cases.
9619 * The second parameter of the constructor, fast_elements, specifies
9620 * whether the storage is a FixedArray or Dictionary.
9621 *
9622 * An index limit is used to deal with the situation that a result array
9623 * length overflows 32-bit non-negative integer.
9624 */
9625class ArrayConcatVisitor {
9626 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009627 ArrayConcatVisitor(Isolate* isolate,
9628 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009629 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009630 isolate_(isolate),
9631 storage_(Handle<FixedArray>::cast(
9632 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009633 index_offset_(0u),
9634 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009635
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009636 ~ArrayConcatVisitor() {
9637 clear_storage();
9638 }
9639
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009640 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009641 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009642 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009643
9644 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009645 if (index < static_cast<uint32_t>(storage_->length())) {
9646 storage_->set(index, *elm);
9647 return;
9648 }
9649 // Our initial estimate of length was foiled, possibly by
9650 // getters on the arrays increasing the length of later arrays
9651 // during iteration.
9652 // This shouldn't happen in anything but pathological cases.
9653 SetDictionaryMode(index);
9654 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009655 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009656 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009657 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009658 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009659 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009660 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009661 // Dictionary needed to grow.
9662 clear_storage();
9663 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009664 }
9665}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009666
9667 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009668 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9669 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009670 } else {
9671 index_offset_ += delta;
9672 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009673 }
9674
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009675 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009676 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009677 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009678 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009679 Handle<Map> map;
9680 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009681 map = isolate_->factory()->GetElementsTransitionMap(array,
9682 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009683 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009684 map = isolate_->factory()->GetElementsTransitionMap(array,
9685 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009686 }
9687 array->set_map(*map);
9688 array->set_length(*length);
9689 array->set_elements(*storage_);
9690 return array;
9691 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009692
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009693 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009694 // Convert storage to dictionary mode.
9695 void SetDictionaryMode(uint32_t index) {
9696 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009697 Handle<FixedArray> current_storage(*storage_);
9698 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009699 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009700 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9701 for (uint32_t i = 0; i < current_length; i++) {
9702 HandleScope loop_scope;
9703 Handle<Object> element(current_storage->get(i));
9704 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009705 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009706 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009707 if (!new_storage.is_identical_to(slow_storage)) {
9708 slow_storage = loop_scope.CloseAndEscape(new_storage);
9709 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009710 }
9711 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009712 clear_storage();
9713 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009714 fast_elements_ = false;
9715 }
9716
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009717 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009718 isolate_->global_handles()->Destroy(
9719 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009720 }
9721
9722 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009723 storage_ = Handle<FixedArray>::cast(
9724 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009725 }
9726
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009727 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009728 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009729 // Index after last seen index. Always less than or equal to
9730 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009731 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009732 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009733};
9734
9735
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009736static uint32_t EstimateElementCount(Handle<JSArray> array) {
9737 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9738 int element_count = 0;
9739 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009740 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009741 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009742 // Fast elements can't have lengths that are not representable by
9743 // a 32-bit signed integer.
9744 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9745 int fast_length = static_cast<int>(length);
9746 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9747 for (int i = 0; i < fast_length; i++) {
9748 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009749 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009750 break;
9751 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009752 case FAST_DOUBLE_ELEMENTS:
9753 // TODO(1810): Decide if it's worthwhile to implement this.
9754 UNREACHABLE();
9755 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009756 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009757 Handle<NumberDictionary> dictionary(
9758 NumberDictionary::cast(array->elements()));
9759 int capacity = dictionary->Capacity();
9760 for (int i = 0; i < capacity; i++) {
9761 Handle<Object> key(dictionary->KeyAt(i));
9762 if (dictionary->IsKey(*key)) {
9763 element_count++;
9764 }
9765 }
9766 break;
9767 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009768 case NON_STRICT_ARGUMENTS_ELEMENTS:
9769 case EXTERNAL_BYTE_ELEMENTS:
9770 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9771 case EXTERNAL_SHORT_ELEMENTS:
9772 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9773 case EXTERNAL_INT_ELEMENTS:
9774 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9775 case EXTERNAL_FLOAT_ELEMENTS:
9776 case EXTERNAL_DOUBLE_ELEMENTS:
9777 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009778 // External arrays are always dense.
9779 return length;
9780 }
9781 // As an estimate, we assume that the prototype doesn't contain any
9782 // inherited elements.
9783 return element_count;
9784}
9785
9786
9787
9788template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009789static void IterateExternalArrayElements(Isolate* isolate,
9790 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009791 bool elements_are_ints,
9792 bool elements_are_guaranteed_smis,
9793 ArrayConcatVisitor* visitor) {
9794 Handle<ExternalArrayClass> array(
9795 ExternalArrayClass::cast(receiver->elements()));
9796 uint32_t len = static_cast<uint32_t>(array->length());
9797
9798 ASSERT(visitor != NULL);
9799 if (elements_are_ints) {
9800 if (elements_are_guaranteed_smis) {
9801 for (uint32_t j = 0; j < len; j++) {
9802 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009803 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009804 visitor->visit(j, e);
9805 }
9806 } else {
9807 for (uint32_t j = 0; j < len; j++) {
9808 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009809 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009810 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9811 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9812 visitor->visit(j, e);
9813 } else {
9814 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009815 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009816 visitor->visit(j, e);
9817 }
9818 }
9819 }
9820 } else {
9821 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009822 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009823 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009824 visitor->visit(j, e);
9825 }
9826 }
9827}
9828
9829
9830// Used for sorting indices in a List<uint32_t>.
9831static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9832 uint32_t a = *ap;
9833 uint32_t b = *bp;
9834 return (a == b) ? 0 : (a < b) ? -1 : 1;
9835}
9836
9837
9838static void CollectElementIndices(Handle<JSObject> object,
9839 uint32_t range,
9840 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009841 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009842 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009843 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009844 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009845 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9846 uint32_t length = static_cast<uint32_t>(elements->length());
9847 if (range < length) length = range;
9848 for (uint32_t i = 0; i < length; i++) {
9849 if (!elements->get(i)->IsTheHole()) {
9850 indices->Add(i);
9851 }
9852 }
9853 break;
9854 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009855 case FAST_DOUBLE_ELEMENTS: {
9856 // TODO(1810): Decide if it's worthwhile to implement this.
9857 UNREACHABLE();
9858 break;
9859 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009860 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009861 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009862 uint32_t capacity = dict->Capacity();
9863 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009864 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009865 Handle<Object> k(dict->KeyAt(j));
9866 if (dict->IsKey(*k)) {
9867 ASSERT(k->IsNumber());
9868 uint32_t index = static_cast<uint32_t>(k->Number());
9869 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009870 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009871 }
9872 }
9873 }
9874 break;
9875 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009876 default: {
9877 int dense_elements_length;
9878 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009879 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009880 dense_elements_length =
9881 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009882 break;
9883 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009884 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009885 dense_elements_length =
9886 ExternalByteArray::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_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009890 dense_elements_length =
9891 ExternalUnsignedByteArray::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_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009895 dense_elements_length =
9896 ExternalShortArray::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_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009900 dense_elements_length =
9901 ExternalUnsignedShortArray::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_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009905 dense_elements_length =
9906 ExternalIntArray::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_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009910 dense_elements_length =
9911 ExternalUnsignedIntArray::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_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009915 dense_elements_length =
9916 ExternalFloatArray::cast(object->elements())->length();
9917 break;
9918 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009919 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009920 dense_elements_length =
9921 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009922 break;
9923 }
9924 default:
9925 UNREACHABLE();
9926 dense_elements_length = 0;
9927 break;
9928 }
9929 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9930 if (range <= length) {
9931 length = range;
9932 // We will add all indices, so we might as well clear it first
9933 // and avoid duplicates.
9934 indices->Clear();
9935 }
9936 for (uint32_t i = 0; i < length; i++) {
9937 indices->Add(i);
9938 }
9939 if (length == range) return; // All indices accounted for already.
9940 break;
9941 }
9942 }
9943
9944 Handle<Object> prototype(object->GetPrototype());
9945 if (prototype->IsJSObject()) {
9946 // The prototype will usually have no inherited element indices,
9947 // but we have to check.
9948 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9949 }
9950}
9951
9952
9953/**
9954 * A helper function that visits elements of a JSArray in numerical
9955 * order.
9956 *
9957 * The visitor argument called for each existing element in the array
9958 * with the element index and the element's value.
9959 * Afterwards it increments the base-index of the visitor by the array
9960 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009961 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009962 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009963static bool IterateElements(Isolate* isolate,
9964 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009965 ArrayConcatVisitor* visitor) {
9966 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9967 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009968 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009969 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009970 // Run through the elements FixedArray and use HasElement and GetElement
9971 // to check the prototype for missing elements.
9972 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9973 int fast_length = static_cast<int>(length);
9974 ASSERT(fast_length <= elements->length());
9975 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009976 HandleScope loop_scope(isolate);
9977 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009978 if (!element_value->IsTheHole()) {
9979 visitor->visit(j, element_value);
9980 } else if (receiver->HasElement(j)) {
9981 // Call GetElement on receiver, not its prototype, or getters won't
9982 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009983 element_value = Object::GetElement(receiver, j);
9984 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009985 visitor->visit(j, element_value);
9986 }
9987 }
9988 break;
9989 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009990 case FAST_DOUBLE_ELEMENTS: {
9991 // TODO(1810): Decide if it's worthwhile to implement this.
9992 UNREACHABLE();
9993 break;
9994 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009995 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009996 Handle<NumberDictionary> dict(receiver->element_dictionary());
9997 List<uint32_t> indices(dict->Capacity() / 2);
9998 // Collect all indices in the object and the prototypes less
9999 // than length. This might introduce duplicates in the indices list.
10000 CollectElementIndices(receiver, length, &indices);
10001 indices.Sort(&compareUInt32);
10002 int j = 0;
10003 int n = indices.length();
10004 while (j < n) {
10005 HandleScope loop_scope;
10006 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010007 Handle<Object> element = Object::GetElement(receiver, index);
10008 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010009 visitor->visit(index, element);
10010 // Skip to next different index (i.e., omit duplicates).
10011 do {
10012 j++;
10013 } while (j < n && indices[j] == index);
10014 }
10015 break;
10016 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010017 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010018 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10019 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010020 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010021 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010022 visitor->visit(j, e);
10023 }
10024 break;
10025 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010026 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010027 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010028 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010029 break;
10030 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010031 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010032 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_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_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010037 IterateExternalArrayElements<ExternalShortArray, int16_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_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010042 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_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_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010047 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010048 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010049 break;
10050 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010051 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010052 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_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_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010057 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010058 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010059 break;
10060 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010061 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010062 IterateExternalArrayElements<ExternalDoubleArray, double>(
10063 isolate, receiver, false, false, visitor);
10064 break;
10065 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010066 default:
10067 UNREACHABLE();
10068 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010069 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010070 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010071 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010072}
10073
10074
10075/**
10076 * Array::concat implementation.
10077 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010078 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010079 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010080 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010081RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010082 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010083 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010084
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010085 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10086 int argument_count = static_cast<int>(arguments->length()->Number());
10087 RUNTIME_ASSERT(arguments->HasFastElements());
10088 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010089
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010090 // Pass 1: estimate the length and number of elements of the result.
10091 // The actual length can be larger if any of the arguments have getters
10092 // that mutate other arguments (but will otherwise be precise).
10093 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010094
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010095 uint32_t estimate_result_length = 0;
10096 uint32_t estimate_nof_elements = 0;
10097 {
10098 for (int i = 0; i < argument_count; i++) {
10099 HandleScope loop_scope;
10100 Handle<Object> obj(elements->get(i));
10101 uint32_t length_estimate;
10102 uint32_t element_estimate;
10103 if (obj->IsJSArray()) {
10104 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010105 // TODO(1810): Find out if it's worthwhile to properly support
10106 // arbitrary ElementsKinds. For now, pessimistically transition to
10107 // FAST_ELEMENTS.
10108 if (array->HasFastDoubleElements()) {
10109 array = Handle<JSArray>::cast(
10110 TransitionElementsKind(array, FAST_ELEMENTS));
10111 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010112 length_estimate =
10113 static_cast<uint32_t>(array->length()->Number());
10114 element_estimate =
10115 EstimateElementCount(array);
10116 } else {
10117 length_estimate = 1;
10118 element_estimate = 1;
10119 }
10120 // Avoid overflows by capping at kMaxElementCount.
10121 if (JSObject::kMaxElementCount - estimate_result_length <
10122 length_estimate) {
10123 estimate_result_length = JSObject::kMaxElementCount;
10124 } else {
10125 estimate_result_length += length_estimate;
10126 }
10127 if (JSObject::kMaxElementCount - estimate_nof_elements <
10128 element_estimate) {
10129 estimate_nof_elements = JSObject::kMaxElementCount;
10130 } else {
10131 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010132 }
10133 }
10134 }
10135
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010136 // If estimated number of elements is more than half of length, a
10137 // fixed array (fast case) is more time and space-efficient than a
10138 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010139 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010140
10141 Handle<FixedArray> storage;
10142 if (fast_case) {
10143 // The backing storage array must have non-existing elements to
10144 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010145 storage = isolate->factory()->NewFixedArrayWithHoles(
10146 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010147 } else {
10148 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10149 uint32_t at_least_space_for = estimate_nof_elements +
10150 (estimate_nof_elements >> 2);
10151 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010152 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010153 }
10154
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010155 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010156
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010157 for (int i = 0; i < argument_count; i++) {
10158 Handle<Object> obj(elements->get(i));
10159 if (obj->IsJSArray()) {
10160 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010161 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010162 return Failure::Exception();
10163 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010164 } else {
10165 visitor.visit(0, obj);
10166 visitor.increase_index_offset(1);
10167 }
10168 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010169
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010170 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010171}
10172
10173
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010174// This will not allocate (flatten the string), but it may run
10175// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010176RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010177 NoHandleAllocation ha;
10178 ASSERT(args.length() == 1);
10179
10180 CONVERT_CHECKED(String, string, args[0]);
10181 StringInputBuffer buffer(string);
10182 while (buffer.has_more()) {
10183 uint16_t character = buffer.GetNext();
10184 PrintF("%c", character);
10185 }
10186 return string;
10187}
10188
ager@chromium.org5ec48922009-05-05 07:25:34 +000010189// Moves all own elements of an object, that are below a limit, to positions
10190// starting at zero. All undefined values are placed after non-undefined values,
10191// and are followed by non-existing element. Does not change the length
10192// property.
10193// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010194RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010195 ASSERT(args.length() == 2);
10196 CONVERT_CHECKED(JSObject, object, args[0]);
10197 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10198 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010199}
10200
10201
10202// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010203RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010204 ASSERT(args.length() == 2);
10205 CONVERT_CHECKED(JSArray, from, args[0]);
10206 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010207 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010208 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010209 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010210 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10211 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010212 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010213 } else if (new_elements->map() ==
10214 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010215 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010216 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010217 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010218 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010219 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010220 Object* new_map;
10221 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010222 to->set_map(Map::cast(new_map));
10223 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010224 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010225 Object* obj;
10226 { MaybeObject* maybe_obj = from->ResetElements();
10227 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10228 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010229 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010230 return to;
10231}
10232
10233
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010234// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010235RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010236 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010237 CONVERT_CHECKED(JSObject, object, args[0]);
10238 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010239 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010240 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010241 } else if (object->IsJSArray()) {
10242 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010243 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010244 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 }
10246}
10247
10248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010249RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010250 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010251
10252 ASSERT_EQ(3, args.length());
10253
ager@chromium.orgac091b72010-05-05 07:34:42 +000010254 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010255 Handle<Object> key1 = args.at<Object>(1);
10256 Handle<Object> key2 = args.at<Object>(2);
10257
10258 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010259 if (!key1->ToArrayIndex(&index1)
10260 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010261 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010262 }
10263
ager@chromium.orgac091b72010-05-05 07:34:42 +000010264 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010265 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010266 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010267 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010268 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010269
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010270 RETURN_IF_EMPTY_HANDLE(isolate,
10271 SetElement(jsobject, index1, tmp2, kStrictMode));
10272 RETURN_IF_EMPTY_HANDLE(isolate,
10273 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010274
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010275 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010276}
10277
10278
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010279// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010280// might have elements. Can either return keys (positive integers) or
10281// intervals (pair of a negative integer (-start-1) followed by a
10282// positive (length)) or undefined values.
10283// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010284RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010285 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010286 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010287 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010288 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010289 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010290 // Create an array and get all the keys into it, then remove all the
10291 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010292 bool threw = false;
10293 Handle<FixedArray> keys =
10294 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10295 if (threw) return Failure::Exception();
10296
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010297 int keys_length = keys->length();
10298 for (int i = 0; i < keys_length; i++) {
10299 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010300 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010301 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010302 // Zap invalid keys.
10303 keys->set_undefined(i);
10304 }
10305 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010306 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010307 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010308 ASSERT(array->HasFastElements() ||
10309 array->HasFastSmiOnlyElements() ||
10310 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010311 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010312 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010313 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010314 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010315 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010316 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010317 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010318 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010319 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010320 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010321 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010322 }
10323}
10324
10325
10326// DefineAccessor takes an optional final argument which is the
10327// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10328// to the way accessors are implemented, it is set for both the getter
10329// and setter on the first call to DefineAccessor and ignored on
10330// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010331RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010332 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10333 // Compute attributes.
10334 PropertyAttributes attributes = NONE;
10335 if (args.length() == 5) {
10336 CONVERT_CHECKED(Smi, attrs, args[4]);
10337 int value = attrs->value();
10338 // Only attribute bits should be set.
10339 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10340 attributes = static_cast<PropertyAttributes>(value);
10341 }
10342
10343 CONVERT_CHECKED(JSObject, obj, args[0]);
10344 CONVERT_CHECKED(String, name, args[1]);
10345 CONVERT_CHECKED(Smi, flag, args[2]);
10346 CONVERT_CHECKED(JSFunction, fun, args[3]);
10347 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10348}
10349
10350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010351RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010352 ASSERT(args.length() == 3);
10353 CONVERT_CHECKED(JSObject, obj, args[0]);
10354 CONVERT_CHECKED(String, name, args[1]);
10355 CONVERT_CHECKED(Smi, flag, args[2]);
10356 return obj->LookupAccessor(name, flag->value() == 0);
10357}
10358
10359
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010360#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010361RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010362 ASSERT(args.length() == 0);
10363 return Execution::DebugBreakHelper();
10364}
10365
10366
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010367// Helper functions for wrapping and unwrapping stack frame ids.
10368static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010369 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010370 return Smi::FromInt(id >> 2);
10371}
10372
10373
10374static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10375 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10376}
10377
10378
10379// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010380// args[0]: debug event listener function to set or null or undefined for
10381// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010382// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010383RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010384 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010385 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10386 args[0]->IsUndefined() ||
10387 args[0]->IsNull());
10388 Handle<Object> callback = args.at<Object>(0);
10389 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010390 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010391
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010392 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010393}
10394
10395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010396RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010397 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010398 isolate->stack_guard()->DebugBreak();
10399 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010400}
10401
10402
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010403static MaybeObject* DebugLookupResultValue(Heap* heap,
10404 Object* receiver,
10405 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010406 LookupResult* result,
10407 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010408 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010409 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010410 case NORMAL:
10411 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010412 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010413 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010414 }
10415 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010416 case FIELD:
10417 value =
10418 JSObject::cast(
10419 result->holder())->FastPropertyAt(result->GetFieldIndex());
10420 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010421 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010422 }
10423 return value;
10424 case CONSTANT_FUNCTION:
10425 return result->GetConstantFunction();
10426 case CALLBACKS: {
10427 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010428 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010429 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10430 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010431 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010432 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010433 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010434 maybe_value = heap->isolate()->pending_exception();
10435 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010436 if (caught_exception != NULL) {
10437 *caught_exception = true;
10438 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010439 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010440 }
10441 return value;
10442 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010443 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010444 }
10445 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010446 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010447 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010448 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010449 case CONSTANT_TRANSITION:
10450 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010451 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010452 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010453 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010454 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010455 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010456 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010457 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010458}
10459
10460
ager@chromium.org32912102009-01-16 10:38:43 +000010461// Get debugger related details for an object property.
10462// args[0]: object holding property
10463// args[1]: name of the property
10464//
10465// The array returned contains the following information:
10466// 0: Property value
10467// 1: Property details
10468// 2: Property value is exception
10469// 3: Getter function if defined
10470// 4: Setter function if defined
10471// Items 2-4 are only filled if the property has either a getter or a setter
10472// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010473RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010474 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010475
10476 ASSERT(args.length() == 2);
10477
10478 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10479 CONVERT_ARG_CHECKED(String, name, 1);
10480
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010481 // Make sure to set the current context to the context before the debugger was
10482 // entered (if the debugger is entered). The reason for switching context here
10483 // is that for some property lookups (accessors and interceptors) callbacks
10484 // into the embedding application can occour, and the embedding application
10485 // could have the assumption that its own global context is the current
10486 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010487 SaveContext save(isolate);
10488 if (isolate->debug()->InDebugger()) {
10489 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010490 }
10491
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010492 // Skip the global proxy as it has no properties and always delegates to the
10493 // real global object.
10494 if (obj->IsJSGlobalProxy()) {
10495 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10496 }
10497
10498
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010499 // Check if the name is trivially convertible to an index and get the element
10500 // if so.
10501 uint32_t index;
10502 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010503 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010504 Object* element_or_char;
10505 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010506 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010507 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10508 return maybe_element_or_char;
10509 }
10510 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010511 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010512 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010513 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010514 }
10515
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010516 // Find the number of objects making up this.
10517 int length = LocalPrototypeChainLength(*obj);
10518
10519 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010520 Handle<JSObject> jsproto = obj;
10521 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010522 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010523 jsproto->LocalLookup(*name, &result);
10524 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010525 // LookupResult is not GC safe as it holds raw object pointers.
10526 // GC can happen later in this code so put the required fields into
10527 // local variables using handles when required for later use.
10528 PropertyType result_type = result.type();
10529 Handle<Object> result_callback_obj;
10530 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010531 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10532 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010533 }
10534 Smi* property_details = result.GetPropertyDetails().AsSmi();
10535 // DebugLookupResultValue can cause GC so details from LookupResult needs
10536 // to be copied to handles before this.
10537 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010538 Object* raw_value;
10539 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010540 DebugLookupResultValue(isolate->heap(), *obj, *name,
10541 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010542 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010544 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010545
10546 // If the callback object is a fixed array then it contains JavaScript
10547 // getter and/or setter.
10548 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10549 result_callback_obj->IsFixedArray();
10550 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010551 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010552 details->set(0, *value);
10553 details->set(1, property_details);
10554 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010555 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010556 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10557 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10558 }
10559
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010560 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010561 }
10562 if (i < length - 1) {
10563 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10564 }
10565 }
10566
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010567 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010568}
10569
10570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010571RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010572 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010573
10574 ASSERT(args.length() == 2);
10575
10576 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10577 CONVERT_ARG_CHECKED(String, name, 1);
10578
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010579 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010580 obj->Lookup(*name, &result);
10581 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010582 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010583 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010584 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010585}
10586
10587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010588// Return the property type calculated from the property details.
10589// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010590RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010591 ASSERT(args.length() == 1);
10592 CONVERT_CHECKED(Smi, details, args[0]);
10593 PropertyType type = PropertyDetails(details).type();
10594 return Smi::FromInt(static_cast<int>(type));
10595}
10596
10597
10598// Return the property attribute calculated from the property details.
10599// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010600RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010601 ASSERT(args.length() == 1);
10602 CONVERT_CHECKED(Smi, details, args[0]);
10603 PropertyAttributes attributes = PropertyDetails(details).attributes();
10604 return Smi::FromInt(static_cast<int>(attributes));
10605}
10606
10607
10608// Return the property insertion index calculated from the property details.
10609// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010610RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010611 ASSERT(args.length() == 1);
10612 CONVERT_CHECKED(Smi, details, args[0]);
10613 int index = PropertyDetails(details).index();
10614 return Smi::FromInt(index);
10615}
10616
10617
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010618// Return property value from named interceptor.
10619// args[0]: object
10620// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010621RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010622 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623 ASSERT(args.length() == 2);
10624 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10625 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10626 CONVERT_ARG_CHECKED(String, name, 1);
10627
10628 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010629 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010630}
10631
10632
10633// Return element value from indexed interceptor.
10634// args[0]: object
10635// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010636RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010637 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010638 ASSERT(args.length() == 2);
10639 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10640 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10641 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10642
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010643 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644}
10645
10646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010647RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010648 ASSERT(args.length() >= 1);
10649 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010650 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010651 if (isolate->debug()->break_id() == 0 ||
10652 break_id != isolate->debug()->break_id()) {
10653 return isolate->Throw(
10654 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010655 }
10656
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010657 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010658}
10659
10660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010661RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010662 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010663 ASSERT(args.length() == 1);
10664
10665 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010666 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010667 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10668 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010669 if (!maybe_result->ToObject(&result)) return maybe_result;
10670 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010671
10672 // Count all frames which are relevant to debugging stack trace.
10673 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010674 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010675 if (id == StackFrame::NO_ID) {
10676 // If there is no JavaScript stack frame count is 0.
10677 return Smi::FromInt(0);
10678 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010679
10680 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10681 n += it.frame()->GetInlineCount();
10682 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010683 return Smi::FromInt(n);
10684}
10685
10686
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010687class FrameInspector {
10688 public:
10689 FrameInspector(JavaScriptFrame* frame,
10690 int inlined_frame_index,
10691 Isolate* isolate)
10692 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10693 // Calculate the deoptimized frame.
10694 if (frame->is_optimized()) {
10695 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10696 frame, inlined_frame_index, isolate);
10697 }
10698 has_adapted_arguments_ = frame_->has_adapted_arguments();
10699 is_optimized_ = frame_->is_optimized();
10700 }
10701
10702 ~FrameInspector() {
10703 // Get rid of the calculated deoptimized frame if any.
10704 if (deoptimized_frame_ != NULL) {
10705 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10706 isolate_);
10707 }
10708 }
10709
10710 int GetParametersCount() {
10711 return is_optimized_
10712 ? deoptimized_frame_->parameters_count()
10713 : frame_->ComputeParametersCount();
10714 }
10715 int expression_count() { return deoptimized_frame_->expression_count(); }
10716 Object* GetFunction() {
10717 return is_optimized_
10718 ? deoptimized_frame_->GetFunction()
10719 : frame_->function();
10720 }
10721 Object* GetParameter(int index) {
10722 return is_optimized_
10723 ? deoptimized_frame_->GetParameter(index)
10724 : frame_->GetParameter(index);
10725 }
10726 Object* GetExpression(int index) {
10727 return is_optimized_
10728 ? deoptimized_frame_->GetExpression(index)
10729 : frame_->GetExpression(index);
10730 }
10731
10732 // To inspect all the provided arguments the frame might need to be
10733 // replaced with the arguments frame.
10734 void SetArgumentsFrame(JavaScriptFrame* frame) {
10735 ASSERT(has_adapted_arguments_);
10736 frame_ = frame;
10737 is_optimized_ = frame_->is_optimized();
10738 ASSERT(!is_optimized_);
10739 }
10740
10741 private:
10742 JavaScriptFrame* frame_;
10743 DeoptimizedFrameInfo* deoptimized_frame_;
10744 Isolate* isolate_;
10745 bool is_optimized_;
10746 bool has_adapted_arguments_;
10747
10748 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10749};
10750
10751
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010752static const int kFrameDetailsFrameIdIndex = 0;
10753static const int kFrameDetailsReceiverIndex = 1;
10754static const int kFrameDetailsFunctionIndex = 2;
10755static const int kFrameDetailsArgumentCountIndex = 3;
10756static const int kFrameDetailsLocalCountIndex = 4;
10757static const int kFrameDetailsSourcePositionIndex = 5;
10758static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010759static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010760static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010761static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010763
10764static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10765 JavaScriptFrame* frame) {
10766 SaveContext* save = isolate->save_context();
10767 while (save != NULL && !save->IsBelowFrame(frame)) {
10768 save = save->prev();
10769 }
10770 ASSERT(save != NULL);
10771 return save;
10772}
10773
10774
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010775// Return an array with frame details
10776// args[0]: number: break id
10777// args[1]: number: frame index
10778//
10779// The array returned contains the following information:
10780// 0: Frame id
10781// 1: Receiver
10782// 2: Function
10783// 3: Argument count
10784// 4: Local count
10785// 5: Source position
10786// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010787// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010788// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010789// Arguments name, value
10790// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010791// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010792RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010793 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010794 ASSERT(args.length() == 2);
10795
10796 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010797 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010798 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10799 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010800 if (!maybe_check->ToObject(&check)) return maybe_check;
10801 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010802 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010803 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010804
10805 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010806 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010807 if (id == StackFrame::NO_ID) {
10808 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010809 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010810 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010811
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010812 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010813
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010814 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010815 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010816 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010817 if (index < count + it.frame()->GetInlineCount()) break;
10818 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010819 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010820 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010821
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010822 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010823 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010824 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010825 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010826 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010827
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010828 // Traverse the saved contexts chain to find the active context for the
10829 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010830 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010831
10832 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010833 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010834
10835 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010836 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010837 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010838
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010839 // Check for constructor frame. Inlined frames cannot be construct calls.
10840 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010841 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010842 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010843
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010844 // Get scope info and read from it for local variable information.
10845 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010846 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010847 Handle<ScopeInfo> scope_info(shared->scope_info());
10848 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010849
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010850 // Get the locals names and values into a temporary array.
10851 //
10852 // TODO(1240907): Hide compiler-introduced stack variables
10853 // (e.g. .result)? For users of the debugger, they will probably be
10854 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010855 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010856 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010857
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010858 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010859 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010860 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010861 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010862 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010863 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010864 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010865 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010866 // Get the context containing declarations.
10867 Handle<Context> context(
10868 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010869 for (; i < scope_info->LocalCount(); ++i) {
10870 Handle<String> name(scope_info->LocalName(i));
10871 VariableMode mode;
10872 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010873 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010874 locals->set(i * 2 + 1, context->get(
10875 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010876 }
10877 }
10878
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010879 // Check whether this frame is positioned at return. If not top
10880 // frame or if the frame is optimized it cannot be at a return.
10881 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010882 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010883 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010884 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010885
10886 // If positioned just before return find the value to be returned and add it
10887 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010888 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010889 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010890 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010891 Address internal_frame_sp = NULL;
10892 while (!it2.done()) {
10893 if (it2.frame()->is_internal()) {
10894 internal_frame_sp = it2.frame()->sp();
10895 } else {
10896 if (it2.frame()->is_java_script()) {
10897 if (it2.frame()->id() == it.frame()->id()) {
10898 // The internal frame just before the JavaScript frame contains the
10899 // value to return on top. A debug break at return will create an
10900 // internal frame to store the return value (eax/rax/r0) before
10901 // entering the debug break exit frame.
10902 if (internal_frame_sp != NULL) {
10903 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010904 Handle<Object>(Memory::Object_at(internal_frame_sp),
10905 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010906 break;
10907 }
10908 }
10909 }
10910
10911 // Indicate that the previous frame was not an internal frame.
10912 internal_frame_sp = NULL;
10913 }
10914 it2.Advance();
10915 }
10916 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010917
10918 // Now advance to the arguments adapter frame (if any). It contains all
10919 // the provided parameters whereas the function frame always have the number
10920 // of arguments matching the functions parameters. The rest of the
10921 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010922 if (it.frame()->has_adapted_arguments()) {
10923 it.AdvanceToArgumentsFrame();
10924 frame_inspector.SetArgumentsFrame(it.frame());
10925 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010926
10927 // Find the number of arguments to fill. At least fill the number of
10928 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010929 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010930 if (argument_count < frame_inspector.GetParametersCount()) {
10931 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010932 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010933#ifdef DEBUG
10934 if (it.frame()->is_optimized()) {
10935 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10936 }
10937#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010938
10939 // Calculate the size of the result.
10940 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010941 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010942 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010943 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010944
10945 // Add the frame id.
10946 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10947
10948 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010949 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950
10951 // Add the arguments count.
10952 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10953
10954 // Add the locals count
10955 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010956 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010957
10958 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010959 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010960 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10961 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010963 }
10964
10965 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010966 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010967
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010968 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010969 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010970
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010971 // Add flags to indicate information on whether this frame is
10972 // bit 0: invoked in the debugger context.
10973 // bit 1: optimized frame.
10974 // bit 2: inlined in optimized frame
10975 int flags = 0;
10976 if (*save->context() == *isolate->debug()->debug_context()) {
10977 flags |= 1 << 0;
10978 }
10979 if (it.frame()->is_optimized()) {
10980 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010981 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010982 }
10983 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010984
10985 // Fill the dynamic part.
10986 int details_index = kFrameDetailsFirstDynamicIndex;
10987
10988 // Add arguments name and value.
10989 for (int i = 0; i < argument_count; i++) {
10990 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010991 if (i < scope_info->ParameterCount()) {
10992 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010993 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010994 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010995 }
10996
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010997 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010998 if (i < it.frame()->ComputeParametersCount()) {
10999 // Get the value from the stack.
11000 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011001 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011002 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011003 }
11004 }
11005
11006 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011007 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011008 details->set(details_index++, locals->get(i));
11009 }
11010
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011011 // Add the value being returned.
11012 if (at_return) {
11013 details->set(details_index++, *return_value);
11014 }
11015
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011016 // Add the receiver (same as in function frame).
11017 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11018 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011019 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011020 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
11021 // If the receiver is not a JSObject and the function is not a
11022 // builtin or strict-mode we have hit an optimization where a
11023 // value object is not converted into a wrapped JS objects. To
11024 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011025 // by creating correct wrapper object based on the calling frame's
11026 // global context.
11027 it.Advance();
11028 Handle<Context> calling_frames_global_context(
11029 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011030 receiver =
11031 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011032 }
11033 details->set(kFrameDetailsReceiverIndex, *receiver);
11034
11035 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011036 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011037}
11038
11039
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011040// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011041static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011042 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011043 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011044 Handle<Context> context,
11045 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011046 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011047 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11048 VariableMode mode;
11049 InitializationFlag init_flag;
11050 int context_index = scope_info->ContextSlotIndex(
11051 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011052
whesse@chromium.org7b260152011-06-20 15:33:18 +000011053 RETURN_IF_EMPTY_HANDLE_VALUE(
11054 isolate,
11055 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011056 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011057 Handle<Object>(context->get(context_index), isolate),
11058 NONE,
11059 kNonStrictMode),
11060 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011061 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011062
11063 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011064}
11065
11066
11067// Create a plain JSObject which materializes the local scope for the specified
11068// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011069static Handle<JSObject> MaterializeLocalScope(
11070 Isolate* isolate,
11071 JavaScriptFrame* frame,
11072 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011073 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011074 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011075 Handle<ScopeInfo> scope_info(shared->scope_info());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011076 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011077
11078 // Allocate and initialize a JSObject with all the arguments, stack locals
11079 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011080 Handle<JSObject> local_scope =
11081 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011082
11083 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011084 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011085 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011086 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011087 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011088 Handle<String>(scope_info->ParameterName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011089 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011090 NONE,
11091 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011092 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011093 }
11094
11095 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011096 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011097 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011098 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011099 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011100 Handle<String>(scope_info->StackLocalName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011101 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011102 NONE,
11103 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011104 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011105 }
11106
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011107 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011108 // Third fill all context locals.
11109 Handle<Context> frame_context(Context::cast(frame->context()));
11110 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011111 if (!CopyContextLocalsToScopeObject(
11112 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011113 return Handle<JSObject>();
11114 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011115
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011116 // Finally copy any properties from the function context extension.
11117 // These will be variables introduced by eval.
11118 if (function_context->closure() == *function) {
11119 if (function_context->has_extension() &&
11120 !function_context->IsGlobalContext()) {
11121 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011122 bool threw = false;
11123 Handle<FixedArray> keys =
11124 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11125 if (threw) return Handle<JSObject>();
11126
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011127 for (int i = 0; i < keys->length(); i++) {
11128 // Names of variables introduced by eval are strings.
11129 ASSERT(keys->get(i)->IsString());
11130 Handle<String> key(String::cast(keys->get(i)));
11131 RETURN_IF_EMPTY_HANDLE_VALUE(
11132 isolate,
11133 SetProperty(local_scope,
11134 key,
11135 GetProperty(ext, key),
11136 NONE,
11137 kNonStrictMode),
11138 Handle<JSObject>());
11139 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011140 }
11141 }
11142 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011143
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011144 return local_scope;
11145}
11146
11147
11148// Create a plain JSObject which materializes the closure content for the
11149// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011150static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11151 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011152 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011153
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011154 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011155 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011156
11157 // Allocate and initialize a JSObject with all the content of theis function
11158 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011159 Handle<JSObject> closure_scope =
11160 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011161
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011162 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011163 if (!CopyContextLocalsToScopeObject(
11164 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011165 return Handle<JSObject>();
11166 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011167
11168 // Finally copy any properties from the function context extension. This will
11169 // be variables introduced by eval.
11170 if (context->has_extension()) {
11171 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011172 bool threw = false;
11173 Handle<FixedArray> keys =
11174 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11175 if (threw) return Handle<JSObject>();
11176
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011177 for (int i = 0; i < keys->length(); i++) {
11178 // Names of variables introduced by eval are strings.
11179 ASSERT(keys->get(i)->IsString());
11180 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011181 RETURN_IF_EMPTY_HANDLE_VALUE(
11182 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011183 SetProperty(closure_scope,
11184 key,
11185 GetProperty(ext, key),
11186 NONE,
11187 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011188 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011189 }
11190 }
11191
11192 return closure_scope;
11193}
11194
11195
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011196// Create a plain JSObject which materializes the scope for the specified
11197// catch context.
11198static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11199 Handle<Context> context) {
11200 ASSERT(context->IsCatchContext());
11201 Handle<String> name(String::cast(context->extension()));
11202 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11203 Handle<JSObject> catch_scope =
11204 isolate->factory()->NewJSObject(isolate->object_function());
11205 RETURN_IF_EMPTY_HANDLE_VALUE(
11206 isolate,
11207 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11208 Handle<JSObject>());
11209 return catch_scope;
11210}
11211
11212
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011213// Create a plain JSObject which materializes the block scope for the specified
11214// block context.
11215static Handle<JSObject> MaterializeBlockScope(
11216 Isolate* isolate,
11217 Handle<Context> context) {
11218 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011219 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011220
11221 // Allocate and initialize a JSObject with all the arguments, stack locals
11222 // heap locals and extension properties of the debugged function.
11223 Handle<JSObject> block_scope =
11224 isolate->factory()->NewJSObject(isolate->object_function());
11225
11226 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011227 if (!CopyContextLocalsToScopeObject(
11228 isolate, scope_info, context, block_scope)) {
11229 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011230 }
11231
11232 return block_scope;
11233}
11234
11235
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011236// Iterate over the actual scopes visible from a stack frame. The iteration
11237// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011238// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011239// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011240class ScopeIterator {
11241 public:
11242 enum ScopeType {
11243 ScopeTypeGlobal = 0,
11244 ScopeTypeLocal,
11245 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011246 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011247 ScopeTypeCatch,
11248 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011249 };
11250
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011251 ScopeIterator(Isolate* isolate,
11252 JavaScriptFrame* frame,
11253 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011254 : isolate_(isolate),
11255 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011256 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011257 function_(JSFunction::cast(frame->function())),
11258 context_(Context::cast(frame->context())),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011259 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011260
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011261 // Catch the case when the debugger stops in an internal function.
11262 Handle<SharedFunctionInfo> shared_info(function_->shared());
11263 if (shared_info->script() == isolate->heap()->undefined_value()) {
11264 while (context_->closure() == *function_) {
11265 context_ = Handle<Context>(context_->previous(), isolate_);
11266 }
11267 return;
11268 }
11269
11270 // Check whether we are in global code or function code. If there is a stack
11271 // slot for .result then this function has been created for evaluating
11272 // global code and it is not a real function.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011273 // Checking for the existence of .result seems fragile, but the scope info
11274 // saved with the code object does not otherwise have that information.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011275 int index = shared_info->scope_info()->
lrn@chromium.org34e60782011-09-15 07:25:40 +000011276 StackSlotIndex(isolate_->heap()->result_symbol());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011277
11278 // Reparse the code and analyze the scopes.
11279 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11280 Handle<Script> script(Script::cast(shared_info->script()));
11281 Scope* scope;
lrn@chromium.org34e60782011-09-15 07:25:40 +000011282 if (index >= 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011283 // Global code
11284 CompilationInfo info(script);
11285 info.MarkAsGlobal();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011286 CHECK(ParserApi::Parse(&info));
11287 CHECK(Scope::Analyze(&info));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011288 scope = info.function()->scope();
11289 } else {
11290 // Function code
11291 CompilationInfo info(shared_info);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011292 CHECK(ParserApi::Parse(&info));
11293 CHECK(Scope::Analyze(&info));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011294 scope = info.function()->scope();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011295 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011296
11297 // Retrieve the scope chain for the current position.
11298 int statement_position =
11299 shared_info->code()->SourceStatementPosition(frame_->pc());
11300 scope->GetNestedScopeChain(&nested_scope_chain_, statement_position);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011301 }
11302
11303 // More scopes?
11304 bool Done() { return context_.is_null(); }
11305
11306 // Move to the next scope.
11307 void Next() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011308 ScopeType scope_type = Type();
11309 if (scope_type == ScopeTypeGlobal) {
11310 // The global scope is always the last in the chain.
11311 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011312 context_ = Handle<Context>();
11313 return;
11314 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011315 if (nested_scope_chain_.is_empty()) {
11316 context_ = Handle<Context>(context_->previous(), isolate_);
11317 } else {
11318 if (nested_scope_chain_.last()->HasContext()) {
11319 context_ = Handle<Context>(context_->previous(), isolate_);
11320 }
11321 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011322 }
11323 }
11324
11325 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011326 ScopeType Type() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011327 if (!nested_scope_chain_.is_empty()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011328 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011329 switch (scope_info->Type()) {
11330 case FUNCTION_SCOPE:
11331 ASSERT(context_->IsFunctionContext() ||
11332 !scope_info->HasContext());
11333 return ScopeTypeLocal;
11334 case GLOBAL_SCOPE:
11335 ASSERT(context_->IsGlobalContext());
11336 return ScopeTypeGlobal;
11337 case WITH_SCOPE:
11338 ASSERT(context_->IsWithContext());
11339 return ScopeTypeWith;
11340 case CATCH_SCOPE:
11341 ASSERT(context_->IsCatchContext());
11342 return ScopeTypeCatch;
11343 case BLOCK_SCOPE:
11344 ASSERT(!scope_info->HasContext() ||
11345 context_->IsBlockContext());
11346 return ScopeTypeBlock;
11347 case EVAL_SCOPE:
11348 UNREACHABLE();
11349 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011350 }
11351 if (context_->IsGlobalContext()) {
11352 ASSERT(context_->global()->IsGlobalObject());
11353 return ScopeTypeGlobal;
11354 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011355 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011356 return ScopeTypeClosure;
11357 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011358 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011359 return ScopeTypeCatch;
11360 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011361 if (context_->IsBlockContext()) {
11362 return ScopeTypeBlock;
11363 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011364 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011365 return ScopeTypeWith;
11366 }
11367
11368 // Return the JavaScript object with the content of the current scope.
11369 Handle<JSObject> ScopeObject() {
11370 switch (Type()) {
11371 case ScopeIterator::ScopeTypeGlobal:
11372 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011373 case ScopeIterator::ScopeTypeLocal:
11374 // Materialize the content of the local scope into a JSObject.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011375 ASSERT(nested_scope_chain_.length() == 1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011376 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011377 case ScopeIterator::ScopeTypeWith:
11378 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011379 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11380 case ScopeIterator::ScopeTypeCatch:
11381 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011382 case ScopeIterator::ScopeTypeClosure:
11383 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011384 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011385 case ScopeIterator::ScopeTypeBlock:
11386 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011387 }
11388 UNREACHABLE();
11389 return Handle<JSObject>();
11390 }
11391
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011392 Handle<ScopeInfo> CurrentScopeInfo() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011393 if (!nested_scope_chain_.is_empty()) {
11394 return nested_scope_chain_.last();
11395 } else if (context_->IsBlockContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011396 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011397 } else if (context_->IsFunctionContext()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011398 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011399 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011400 return Handle<ScopeInfo>::null();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011401 }
11402
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011403 // Return the context for this scope. For the local context there might not
11404 // be an actual context.
11405 Handle<Context> CurrentContext() {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011406 if (Type() == ScopeTypeGlobal ||
11407 nested_scope_chain_.is_empty()) {
11408 return context_;
11409 } else if (nested_scope_chain_.last()->HasContext()) {
11410 return context_;
11411 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011412 return Handle<Context>();
11413 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011414 }
11415
11416#ifdef DEBUG
11417 // Debug print of the content of the current scope.
11418 void DebugPrint() {
11419 switch (Type()) {
11420 case ScopeIterator::ScopeTypeGlobal:
11421 PrintF("Global:\n");
11422 CurrentContext()->Print();
11423 break;
11424
11425 case ScopeIterator::ScopeTypeLocal: {
11426 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011427 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011428 if (!CurrentContext().is_null()) {
11429 CurrentContext()->Print();
11430 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011431 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011432 if (extension->IsJSContextExtensionObject()) {
11433 extension->Print();
11434 }
11435 }
11436 }
11437 break;
11438 }
11439
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011440 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011441 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011442 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011443 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011444
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011445 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011446 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011447 CurrentContext()->extension()->Print();
11448 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011449 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011450
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011451 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011452 PrintF("Closure:\n");
11453 CurrentContext()->Print();
11454 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011455 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011456 if (extension->IsJSContextExtensionObject()) {
11457 extension->Print();
11458 }
11459 }
11460 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011461
11462 default:
11463 UNREACHABLE();
11464 }
11465 PrintF("\n");
11466 }
11467#endif
11468
11469 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011470 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011471 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011472 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011473 Handle<JSFunction> function_;
11474 Handle<Context> context_;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011475 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011476
11477 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11478};
11479
11480
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011481RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011482 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011483 ASSERT(args.length() == 2);
11484
11485 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011486 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011487 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11488 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011489 if (!maybe_check->ToObject(&check)) return maybe_check;
11490 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011491 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11492
11493 // Get the frame where the debugging is performed.
11494 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011495 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011496 JavaScriptFrame* frame = it.frame();
11497
11498 // Count the visible scopes.
11499 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011500 for (ScopeIterator it(isolate, frame, 0);
11501 !it.Done();
11502 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011503 n++;
11504 }
11505
11506 return Smi::FromInt(n);
11507}
11508
11509
11510static const int kScopeDetailsTypeIndex = 0;
11511static const int kScopeDetailsObjectIndex = 1;
11512static const int kScopeDetailsSize = 2;
11513
11514// Return an array with scope details
11515// args[0]: number: break id
11516// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011517// args[2]: number: inlined frame index
11518// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011519//
11520// The array returned contains the following information:
11521// 0: Scope type
11522// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011523RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011524 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011525 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011526
11527 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011528 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011529 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11530 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011531 if (!maybe_check->ToObject(&check)) return maybe_check;
11532 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011533 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011534 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11535 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011536
11537 // Get the frame where the debugging is performed.
11538 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011539 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011540 JavaScriptFrame* frame = frame_it.frame();
11541
11542 // Find the requested scope.
11543 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011544 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011545 for (; !it.Done() && n < index; it.Next()) {
11546 n++;
11547 }
11548 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011549 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011550 }
11551
11552 // Calculate the size of the result.
11553 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011554 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011555
11556 // Fill in scope details.
11557 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011558 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011559 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011560 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011561
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011562 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011563}
11564
11565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011566RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011567 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011568 ASSERT(args.length() == 0);
11569
11570#ifdef DEBUG
11571 // Print the scopes for the top frame.
11572 StackFrameLocator locator;
11573 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011574 for (ScopeIterator it(isolate, frame, 0);
11575 !it.Done();
11576 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011577 it.DebugPrint();
11578 }
11579#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011580 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011581}
11582
11583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011584RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011585 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011586 ASSERT(args.length() == 1);
11587
11588 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011589 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011590 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11591 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011592 if (!maybe_result->ToObject(&result)) return maybe_result;
11593 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011594
11595 // Count all archived V8 threads.
11596 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011597 for (ThreadState* thread =
11598 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011599 thread != NULL;
11600 thread = thread->Next()) {
11601 n++;
11602 }
11603
11604 // Total number of threads is current thread and archived threads.
11605 return Smi::FromInt(n + 1);
11606}
11607
11608
11609static const int kThreadDetailsCurrentThreadIndex = 0;
11610static const int kThreadDetailsThreadIdIndex = 1;
11611static const int kThreadDetailsSize = 2;
11612
11613// Return an array with thread details
11614// args[0]: number: break id
11615// args[1]: number: thread index
11616//
11617// The array returned contains the following information:
11618// 0: Is current thread?
11619// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011620RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011621 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011622 ASSERT(args.length() == 2);
11623
11624 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011625 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011626 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11627 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011628 if (!maybe_check->ToObject(&check)) return maybe_check;
11629 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011630 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11631
11632 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011633 Handle<FixedArray> details =
11634 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011635
11636 // Thread index 0 is current thread.
11637 if (index == 0) {
11638 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011639 details->set(kThreadDetailsCurrentThreadIndex,
11640 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011641 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011642 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011643 } else {
11644 // Find the thread with the requested index.
11645 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 ThreadState* thread =
11647 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011648 while (index != n && thread != NULL) {
11649 thread = thread->Next();
11650 n++;
11651 }
11652 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011653 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011654 }
11655
11656 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011657 details->set(kThreadDetailsCurrentThreadIndex,
11658 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011659 details->set(kThreadDetailsThreadIdIndex,
11660 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011661 }
11662
11663 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011664 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011665}
11666
11667
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011668// Sets the disable break state
11669// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011670RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011671 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011672 ASSERT(args.length() == 1);
11673 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011674 isolate->debug()->set_disable_break(disable_break);
11675 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011676}
11677
11678
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011679RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011680 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011681 ASSERT(args.length() == 1);
11682
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011683 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11684 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011685 // Find the number of break points
11686 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011687 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011688 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011689 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011690 Handle<FixedArray>::cast(break_locations));
11691}
11692
11693
11694// Set a break point in a function
11695// args[0]: function
11696// args[1]: number: break source position (within the function source)
11697// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011698RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011699 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011700 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011701 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11702 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011703 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11704 RUNTIME_ASSERT(source_position >= 0);
11705 Handle<Object> break_point_object_arg = args.at<Object>(2);
11706
11707 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011708 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11709 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011710
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011711 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011712}
11713
11714
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011715Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11716 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011717 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011718 // Iterate the heap looking for SharedFunctionInfo generated from the
11719 // script. The inner most SharedFunctionInfo containing the source position
11720 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011721 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011722 // which is found is not compiled it is compiled and the heap is iterated
11723 // again as the compilation might create inner functions from the newly
11724 // compiled function and the actual requested break point might be in one of
11725 // these functions.
11726 bool done = false;
11727 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011728 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011729 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011730 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011731 { // Extra scope for iterator and no-allocation.
11732 isolate->heap()->EnsureHeapIsIterable();
11733 AssertNoAllocation no_alloc_during_heap_iteration;
11734 HeapIterator iterator;
11735 for (HeapObject* obj = iterator.next();
11736 obj != NULL; obj = iterator.next()) {
11737 if (obj->IsSharedFunctionInfo()) {
11738 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11739 if (shared->script() == *script) {
11740 // If the SharedFunctionInfo found has the requested script data and
11741 // contains the source position it is a candidate.
11742 int start_position = shared->function_token_position();
11743 if (start_position == RelocInfo::kNoPosition) {
11744 start_position = shared->start_position();
11745 }
11746 if (start_position <= position &&
11747 position <= shared->end_position()) {
11748 // If there is no candidate or this function is within the current
11749 // candidate this is the new candidate.
11750 if (target.is_null()) {
11751 target_start_position = start_position;
11752 target = shared;
11753 } else {
11754 if (target_start_position == start_position &&
11755 shared->end_position() == target->end_position()) {
11756 // If a top-level function contain only one function
11757 // declartion the source for the top-level and the
11758 // function is the same. In that case prefer the non
11759 // top-level function.
11760 if (!shared->is_toplevel()) {
11761 target_start_position = start_position;
11762 target = shared;
11763 }
11764 } else if (target_start_position <= start_position &&
11765 shared->end_position() <= target->end_position()) {
11766 // This containment check includes equality as a function
11767 // inside a top-level function can share either start or end
11768 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011769 target_start_position = start_position;
11770 target = shared;
11771 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 }
11773 }
11774 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011775 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011776 } // End for loop.
11777 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011778
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011779 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011780 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011781 }
11782
11783 // If the candidate found is compiled we are done. NOTE: when lazy
11784 // compilation of inner functions is introduced some additional checking
11785 // needs to be done here to compile inner functions.
11786 done = target->is_compiled();
11787 if (!done) {
11788 // If the candidate is not compiled compile it to reveal any inner
11789 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011790 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011791 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011792 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011793
11794 return *target;
11795}
11796
11797
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011798// Changes the state of a break point in a script and returns source position
11799// where break point was set. NOTE: Regarding performance see the NOTE for
11800// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011801// args[0]: script to set break point in
11802// args[1]: number: break source position (within the script source)
11803// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011804RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011805 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011806 ASSERT(args.length() == 3);
11807 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11808 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11809 RUNTIME_ASSERT(source_position >= 0);
11810 Handle<Object> break_point_object_arg = args.at<Object>(2);
11811
11812 // Get the script from the script wrapper.
11813 RUNTIME_ASSERT(wrapper->value()->IsScript());
11814 Handle<Script> script(Script::cast(wrapper->value()));
11815
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011816 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011817 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011818 if (!result->IsUndefined()) {
11819 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11820 // Find position within function. The script position might be before the
11821 // source position of the first function.
11822 int position;
11823 if (shared->start_position() > source_position) {
11824 position = 0;
11825 } else {
11826 position = source_position - shared->start_position();
11827 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011828 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011829 position += shared->start_position();
11830 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011831 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011832 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011833}
11834
11835
11836// Clear a break point
11837// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011838RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011839 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011840 ASSERT(args.length() == 1);
11841 Handle<Object> break_point_object_arg = args.at<Object>(0);
11842
11843 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011844 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011845
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011846 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011847}
11848
11849
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011850// Change the state of break on exceptions.
11851// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11852// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011853RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011854 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011855 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011856 RUNTIME_ASSERT(args[0]->IsNumber());
11857 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011858
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011859 // If the number doesn't match an enum value, the ChangeBreakOnException
11860 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011861 ExceptionBreakType type =
11862 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011863 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011864 isolate->debug()->ChangeBreakOnException(type, enable);
11865 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011866}
11867
11868
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011869// Returns the state of break on exceptions
11870// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011871RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011872 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011873 ASSERT(args.length() == 1);
11874 RUNTIME_ASSERT(args[0]->IsNumber());
11875
11876 ExceptionBreakType type =
11877 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011878 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011879 return Smi::FromInt(result);
11880}
11881
11882
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011883// Prepare for stepping
11884// args[0]: break id for checking execution state
11885// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011886// args[2]: number of times to perform the step, for step out it is the number
11887// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011888RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011889 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011890 ASSERT(args.length() == 3);
11891 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011892 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011893 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11894 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011895 if (!maybe_check->ToObject(&check)) return maybe_check;
11896 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011897 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011898 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011899 }
11900
11901 // Get the step action and check validity.
11902 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11903 if (step_action != StepIn &&
11904 step_action != StepNext &&
11905 step_action != StepOut &&
11906 step_action != StepInMin &&
11907 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011908 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011909 }
11910
11911 // Get the number of steps.
11912 int step_count = NumberToInt32(args[2]);
11913 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011914 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011915 }
11916
ager@chromium.orga1645e22009-09-09 19:27:10 +000011917 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011918 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011919
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011920 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011921 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11922 step_count);
11923 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011924}
11925
11926
11927// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011928RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011929 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011930 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011931 isolate->debug()->ClearStepping();
11932 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011933}
11934
11935
11936// Creates a copy of the with context chain. The copy of the context chain is
11937// is linked to the function context supplied.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011938static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11939 Handle<JSFunction> function,
11940 Handle<Context> base,
11941 JavaScriptFrame* frame,
11942 int inlined_frame_index) {
11943 HandleScope scope(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011944 List<Handle<ScopeInfo> > scope_chain;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011945 List<Handle<Context> > context_chain;
11946
11947 ScopeIterator it(isolate, frame, inlined_frame_index);
11948 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11949 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11950 ASSERT(!it.Done());
11951 scope_chain.Add(it.CurrentScopeInfo());
11952 context_chain.Add(it.CurrentContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011953 }
11954
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011955 // At the end of the chain. Return the base context to link to.
11956 Handle<Context> context = base;
11957
11958 // Iteratively copy and or materialize the nested contexts.
11959 while (!scope_chain.is_empty()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011960 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011961 Handle<Context> current = context_chain.RemoveLast();
11962 ASSERT(!(scope_info->HasContext() & current.is_null()));
11963
11964 if (scope_info->Type() == CATCH_SCOPE) {
11965 Handle<String> name(String::cast(current->extension()));
11966 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11967 context =
11968 isolate->factory()->NewCatchContext(function,
11969 context,
11970 name,
11971 thrown_object);
11972 } else if (scope_info->Type() == BLOCK_SCOPE) {
11973 // Materialize the contents of the block scope into a JSObject.
11974 Handle<JSObject> block_scope_object =
11975 MaterializeBlockScope(isolate, current);
11976 if (block_scope_object.is_null()) {
11977 return Handle<Context>::null();
11978 }
11979 // Allocate a new function context for the debug evaluation and set the
11980 // extension object.
11981 Handle<Context> new_context =
11982 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11983 function);
11984 new_context->set_extension(*block_scope_object);
11985 new_context->set_previous(*context);
11986 context = new_context;
11987 } else {
11988 ASSERT(scope_info->Type() == WITH_SCOPE);
11989 ASSERT(current->IsWithContext());
11990 Handle<JSObject> extension(JSObject::cast(current->extension()));
11991 context =
11992 isolate->factory()->NewWithContext(function, context, extension);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011993 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011994 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011995
11996 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011997}
11998
11999
12000// Helper function to find or create the arguments object for
12001// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012002static Handle<Object> GetArgumentsObject(Isolate* isolate,
12003 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012004 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012005 Handle<JSFunction> function,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012006 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012007 Handle<Context> function_context) {
12008 // Try to find the value of 'arguments' to pass as parameter. If it is not
12009 // found (that is the debugged function does not reference 'arguments' and
12010 // does not support eval) then create an 'arguments' object.
12011 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012012 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012013 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012014 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012015 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012016 }
12017 }
12018
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012019 if (scope_info->HasHeapAllocatedLocals()) {
12020 VariableMode mode;
12021 InitializationFlag init_flag;
12022 index = scope_info->ContextSlotIndex(
12023 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012024 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012025 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012026 }
12027 }
12028
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012029 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
12030
12031 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012032 Handle<JSObject> arguments =
12033 isolate->factory()->NewArgumentsObject(function, length);
12034 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012035
12036 AssertNoAllocation no_gc;
12037 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012038 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012039 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012040 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012041 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012042 return arguments;
12043}
12044
12045
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012046static const char kSourceStr[] =
12047 "(function(arguments,__source__){return eval(__source__);})";
12048
12049
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012050// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012051// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012052// extension part has all the parameters and locals of the function on the
12053// stack frame. A function which calls eval with the code to evaluate is then
12054// compiled in this context and called in this context. As this context
12055// replaces the context of the function on the stack frame a new (empty)
12056// function is created as well to be used as the closure for the context.
12057// This function and the context acts as replacements for the function on the
12058// stack frame presenting the same view of the values of parameters and
12059// local variables as if the piece of JavaScript was evaluated at the point
12060// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012061RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012062 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012063
12064 // Check the execution state and decode arguments frame and source to be
12065 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012066 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012067 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012068 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12069 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012070 if (!maybe_check_result->ToObject(&check_result)) {
12071 return maybe_check_result;
12072 }
12073 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012074 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012075 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
12076 CONVERT_ARG_CHECKED(String, source, 3);
12077 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12078 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012079
12080 // Handle the processing of break.
12081 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012082
12083 // Get the frame where the debugging is performed.
12084 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012085 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012086 JavaScriptFrame* frame = it.frame();
12087 Handle<JSFunction> function(JSFunction::cast(frame->function()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012088 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012089
12090 // Traverse the saved contexts chain to find the active context for the
12091 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012092 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12093
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012094 SaveContext savex(isolate);
12095 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012096
12097 // Create the (empty) function replacing the function on the stack frame for
12098 // the purpose of evaluating in the context created below. It is important
12099 // that this function does not describe any parameters and local variables
12100 // in the context. If it does then this will cause problems with the lookup
12101 // in Context::Lookup, where context slots for parameters and local variables
12102 // are looked at before the extension object.
12103 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012104 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12105 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012106 go_between->set_context(function->context());
12107#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012108 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12109 ASSERT(go_between_scope_info->ParameterCount() == 0);
12110 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012111#endif
12112
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012113 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012114 Handle<JSObject> local_scope = MaterializeLocalScope(
12115 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012116 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012117
12118 // Allocate a new context for the debug evaluation and set the extension
12119 // object build.
12120 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012121 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12122 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012123 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012124 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012125 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012126 Handle<Context> function_context;
12127 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012128 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012129 function_context = Handle<Context>(frame_context->declaration_context());
12130 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012131 context = CopyNestedScopeContextChain(isolate,
12132 go_between,
12133 context,
12134 frame,
12135 inlined_frame_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012136
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012137 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012138 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012139 context =
12140 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012141 }
12142
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012143 // Wrap the evaluation statement in a new function compiled in the newly
12144 // created context. The function has one parameter which has to be called
12145 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012146 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012147 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012148
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012149 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012150 isolate->factory()->NewStringFromAscii(
12151 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012152
12153 // Currently, the eval code will be executed in non-strict mode,
12154 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012155 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012156 Compiler::CompileEval(function_source,
12157 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012158 context->IsGlobalContext(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012159 kNonStrictMode,
12160 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012161 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012162 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012163 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012164
12165 // Invoke the result of the compilation to get the evaluation function.
12166 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012167 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012168 Handle<Object> evaluation_function =
12169 Execution::Call(compiled_function, receiver, 0, NULL,
12170 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012171 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012172
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012173 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012174 frame,
12175 inlined_frame_index,
12176 function,
12177 scope_info,
12178 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012179
12180 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012181 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012182 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012183 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12184 receiver,
12185 ARRAY_SIZE(argv),
12186 argv,
12187 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012188 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012189
12190 // Skip the global proxy as it has no properties and always delegates to the
12191 // real global object.
12192 if (result->IsJSGlobalProxy()) {
12193 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12194 }
12195
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012196 return *result;
12197}
12198
12199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012200RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012201 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012202
12203 // Check the execution state and decode arguments frame and source to be
12204 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012205 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012206 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012207 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12208 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012209 if (!maybe_check_result->ToObject(&check_result)) {
12210 return maybe_check_result;
12211 }
12212 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012213 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012214 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012215 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012216
12217 // Handle the processing of break.
12218 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012219
12220 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012221 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012222 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012223 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012224 top = top->prev();
12225 }
12226 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012227 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012228 }
12229
12230 // Get the global context now set to the top context from before the
12231 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012232 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012233
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012234 bool is_global = true;
12235
12236 if (additional_context->IsJSObject()) {
12237 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012238 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
12239 isolate->factory()->empty_string(),
12240 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012241 go_between->set_context(*context);
12242 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012243 isolate->factory()->NewFunctionContext(
12244 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012245 context->set_extension(JSObject::cast(*additional_context));
12246 is_global = false;
12247 }
12248
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012249 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012250 // Currently, the eval code will be executed in non-strict mode,
12251 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012252 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012253 Compiler::CompileEval(source,
12254 context,
12255 is_global,
12256 kNonStrictMode,
12257 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012258 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012259 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012260 Handle<JSFunction>(
12261 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12262 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012263
12264 // Invoke the result of the compilation to get the evaluation function.
12265 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012266 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012267 Handle<Object> result =
12268 Execution::Call(compiled_function, receiver, 0, NULL,
12269 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012270 // Clear the oneshot breakpoints so that the debugger does not step further.
12271 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012272 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012273 return *result;
12274}
12275
12276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012277RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012278 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012279 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012281 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012282 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012283
12284 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012285 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012286 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12287 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12288 // because using
12289 // instances->set(i, *GetScriptWrapper(script))
12290 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12291 // already have deferenced the instances handle.
12292 Handle<JSValue> wrapper = GetScriptWrapper(script);
12293 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012294 }
12295
12296 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012297 Handle<JSObject> result =
12298 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012299 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012300 return *result;
12301}
12302
12303
12304// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012305static int DebugReferencedBy(HeapIterator* iterator,
12306 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012307 Object* instance_filter, int max_references,
12308 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012309 JSFunction* arguments_function) {
12310 NoHandleAllocation ha;
12311 AssertNoAllocation no_alloc;
12312
12313 // Iterate the heap.
12314 int count = 0;
12315 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012316 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012317 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012318 (max_references == 0 || count < max_references)) {
12319 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012320 if (heap_obj->IsJSObject()) {
12321 // Skip context extension objects and argument arrays as these are
12322 // checked in the context of functions using them.
12323 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012324 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012325 obj->map()->constructor() == arguments_function) {
12326 continue;
12327 }
12328
12329 // Check if the JS object has a reference to the object looked for.
12330 if (obj->ReferencesObject(target)) {
12331 // Check instance filter if supplied. This is normally used to avoid
12332 // references from mirror objects (see Runtime_IsInPrototypeChain).
12333 if (!instance_filter->IsUndefined()) {
12334 Object* V = obj;
12335 while (true) {
12336 Object* prototype = V->GetPrototype();
12337 if (prototype->IsNull()) {
12338 break;
12339 }
12340 if (instance_filter == prototype) {
12341 obj = NULL; // Don't add this object.
12342 break;
12343 }
12344 V = prototype;
12345 }
12346 }
12347
12348 if (obj != NULL) {
12349 // Valid reference found add to instance array if supplied an update
12350 // count.
12351 if (instances != NULL && count < instances_size) {
12352 instances->set(count, obj);
12353 }
12354 last = obj;
12355 count++;
12356 }
12357 }
12358 }
12359 }
12360
12361 // Check for circular reference only. This can happen when the object is only
12362 // referenced from mirrors and has a circular reference in which case the
12363 // object is not really alive and would have been garbage collected if not
12364 // referenced from the mirror.
12365 if (count == 1 && last == target) {
12366 count = 0;
12367 }
12368
12369 // Return the number of referencing objects found.
12370 return count;
12371}
12372
12373
12374// Scan the heap for objects with direct references to an object
12375// args[0]: the object to find references to
12376// args[1]: constructor function for instances to exclude (Mirror)
12377// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012378RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012379 ASSERT(args.length() == 3);
12380
12381 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012382 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12383 // The heap iterator reserves the right to do a GC to make the heap iterable.
12384 // Due to the GC above we know it won't need to do that, but it seems cleaner
12385 // to get the heap iterator constructed before we start having unprotected
12386 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012387
12388 // Check parameters.
12389 CONVERT_CHECKED(JSObject, target, args[0]);
12390 Object* instance_filter = args[1];
12391 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12392 instance_filter->IsJSObject());
12393 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12394 RUNTIME_ASSERT(max_references >= 0);
12395
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012396
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012397 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012398 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012399 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012400 JSFunction* arguments_function =
12401 JSFunction::cast(arguments_boilerplate->map()->constructor());
12402
12403 // Get the number of referencing objects.
12404 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012405 HeapIterator heap_iterator;
12406 count = DebugReferencedBy(&heap_iterator,
12407 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012408 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012409
12410 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012411 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012412 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012413 if (!maybe_object->ToObject(&object)) return maybe_object;
12414 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012415 FixedArray* instances = FixedArray::cast(object);
12416
12417 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012418 // AllocateFixedArray above does not make the heap non-iterable.
12419 ASSERT(HEAP->IsHeapIterable());
12420 HeapIterator heap_iterator2;
12421 count = DebugReferencedBy(&heap_iterator2,
12422 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012423 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012424
12425 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012426 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012427 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012428 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012429 if (!maybe_result->ToObject(&result)) return maybe_result;
12430 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012431}
12432
12433
12434// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012435static int DebugConstructedBy(HeapIterator* iterator,
12436 JSFunction* constructor,
12437 int max_references,
12438 FixedArray* instances,
12439 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012440 AssertNoAllocation no_alloc;
12441
12442 // Iterate the heap.
12443 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012444 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012445 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012446 (max_references == 0 || count < max_references)) {
12447 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012448 if (heap_obj->IsJSObject()) {
12449 JSObject* obj = JSObject::cast(heap_obj);
12450 if (obj->map()->constructor() == constructor) {
12451 // Valid reference found add to instance array if supplied an update
12452 // count.
12453 if (instances != NULL && count < instances_size) {
12454 instances->set(count, obj);
12455 }
12456 count++;
12457 }
12458 }
12459 }
12460
12461 // Return the number of referencing objects found.
12462 return count;
12463}
12464
12465
12466// Scan the heap for objects constructed by a specific function.
12467// args[0]: the constructor to find instances of
12468// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012469RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012470 ASSERT(args.length() == 2);
12471
12472 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012473 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012474
12475 // Check parameters.
12476 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12477 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12478 RUNTIME_ASSERT(max_references >= 0);
12479
12480 // Get the number of referencing objects.
12481 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012482 HeapIterator heap_iterator;
12483 count = DebugConstructedBy(&heap_iterator,
12484 constructor,
12485 max_references,
12486 NULL,
12487 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012488
12489 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012490 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012491 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012492 if (!maybe_object->ToObject(&object)) return maybe_object;
12493 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012494 FixedArray* instances = FixedArray::cast(object);
12495
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012496 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012497 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012498 HeapIterator heap_iterator2;
12499 count = DebugConstructedBy(&heap_iterator2,
12500 constructor,
12501 max_references,
12502 instances,
12503 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012504
12505 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012506 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012507 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12508 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012509 if (!maybe_result->ToObject(&result)) return maybe_result;
12510 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012511 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012512}
12513
12514
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012515// Find the effective prototype object as returned by __proto__.
12516// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012517RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012518 ASSERT(args.length() == 1);
12519
12520 CONVERT_CHECKED(JSObject, obj, args[0]);
12521
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012522 // Use the __proto__ accessor.
12523 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012524}
12525
12526
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012527RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012528 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012529 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012530 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012531}
12532
12533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012534RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012535#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012536 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012537 ASSERT(args.length() == 1);
12538 // Get the function and make sure it is compiled.
12539 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012540 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012541 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012542 return Failure::Exception();
12543 }
12544 func->code()->PrintLn();
12545#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012546 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012547}
ager@chromium.org9085a012009-05-11 19:22:57 +000012548
12549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012550RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012551#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012552 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012553 ASSERT(args.length() == 1);
12554 // Get the function and make sure it is compiled.
12555 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012556 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012557 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012558 return Failure::Exception();
12559 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012560 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012561#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012562 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012563}
12564
12565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012566RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012567 NoHandleAllocation ha;
12568 ASSERT(args.length() == 1);
12569
12570 CONVERT_CHECKED(JSFunction, f, args[0]);
12571 return f->shared()->inferred_name();
12572}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012573
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012574
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012575static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12576 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012577 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012578 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012579 int counter = 0;
12580 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012581 for (HeapObject* obj = iterator->next();
12582 obj != NULL;
12583 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012584 ASSERT(obj != NULL);
12585 if (!obj->IsSharedFunctionInfo()) {
12586 continue;
12587 }
12588 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12589 if (shared->script() != script) {
12590 continue;
12591 }
12592 if (counter < buffer_size) {
12593 buffer->set(counter, shared);
12594 }
12595 counter++;
12596 }
12597 return counter;
12598}
12599
12600// For a script finds all SharedFunctionInfo's in the heap that points
12601// to this script. Returns JSArray of SharedFunctionInfo wrapped
12602// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012603RUNTIME_FUNCTION(MaybeObject*,
12604 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012605 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012606 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012607 CONVERT_CHECKED(JSValue, script_value, args[0]);
12608
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012609
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012610 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12611
12612 const int kBufferSize = 32;
12613
12614 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012615 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012616 int number;
12617 {
12618 isolate->heap()->EnsureHeapIsIterable();
12619 AssertNoAllocation no_allocations;
12620 HeapIterator heap_iterator;
12621 Script* scr = *script;
12622 FixedArray* arr = *array;
12623 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12624 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012625 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012626 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012627 isolate->heap()->EnsureHeapIsIterable();
12628 AssertNoAllocation no_allocations;
12629 HeapIterator heap_iterator;
12630 Script* scr = *script;
12631 FixedArray* arr = *array;
12632 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012633 }
12634
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012635 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012636 result->set_length(Smi::FromInt(number));
12637
12638 LiveEdit::WrapSharedFunctionInfos(result);
12639
12640 return *result;
12641}
12642
12643// For a script calculates compilation information about all its functions.
12644// The script source is explicitly specified by the second argument.
12645// The source of the actual script is not used, however it is important that
12646// all generated code keeps references to this particular instance of script.
12647// Returns a JSArray of compilation infos. The array is ordered so that
12648// each function with all its descendant is always stored in a continues range
12649// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012650RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012651 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012652 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012653 CONVERT_CHECKED(JSValue, script, args[0]);
12654 CONVERT_ARG_CHECKED(String, source, 1);
12655 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12656
12657 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12658
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012659 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012660 return Failure::Exception();
12661 }
12662
12663 return result;
12664}
12665
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012666// Changes the source of the script to a new_source.
12667// If old_script_name is provided (i.e. is a String), also creates a copy of
12668// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012669RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012670 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012671 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012672 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12673 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012674 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012675
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012676 CONVERT_CHECKED(Script, original_script_pointer,
12677 original_script_value->value());
12678 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012679
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012680 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12681 new_source,
12682 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012683
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012684 if (old_script->IsScript()) {
12685 Handle<Script> script_handle(Script::cast(old_script));
12686 return *(GetScriptWrapper(script_handle));
12687 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012688 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012689 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012690}
12691
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012692
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012693RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012694 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012695 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012696 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12697 return LiveEdit::FunctionSourceUpdated(shared_info);
12698}
12699
12700
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012701// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012702RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012703 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012704 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012705 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12706 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12707
ager@chromium.orgac091b72010-05-05 07:34:42 +000012708 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012709}
12710
12711// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012712RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012713 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012714 HandleScope scope(isolate);
12715 Handle<Object> function_object(args[0], isolate);
12716 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012717
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012718 if (function_object->IsJSValue()) {
12719 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12720 if (script_object->IsJSValue()) {
12721 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012722 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012723 }
12724
12725 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12726 } else {
12727 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12728 // and we check it in this function.
12729 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012730
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012731 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012732}
12733
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012734
12735// In a code of a parent function replaces original function as embedded object
12736// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012737RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012738 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012739 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012740
12741 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12742 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12743 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12744
12745 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12746 subst_wrapper);
12747
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012748 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012749}
12750
12751
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012752// Updates positions of a shared function info (first parameter) according
12753// to script source change. Text change is described in second parameter as
12754// array of groups of 3 numbers:
12755// (change_begin, change_end, change_end_new_position).
12756// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012757RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012758 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012759 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012760 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12761 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12762
ager@chromium.orgac091b72010-05-05 07:34:42 +000012763 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012764}
12765
12766
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012767// For array of SharedFunctionInfo's (each wrapped in JSValue)
12768// checks that none of them have activations on stacks (of any thread).
12769// Returns array of the same length with corresponding results of
12770// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012771RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012772 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012773 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012774 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012775 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012776
ager@chromium.org357bf652010-04-12 11:30:10 +000012777 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012778}
12779
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012780// Compares 2 strings line-by-line, then token-wise and returns diff in form
12781// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12782// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012783RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012784 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012785 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012786 CONVERT_ARG_CHECKED(String, s1, 0);
12787 CONVERT_ARG_CHECKED(String, s2, 1);
12788
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012789 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012790}
12791
12792
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012793// A testing entry. Returns statement position which is the closest to
12794// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012795RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012796 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012797 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012798 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12799 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12800
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012801 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012802
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012803 if (code->kind() != Code::FUNCTION &&
12804 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012805 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012806 }
12807
12808 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012809 int closest_pc = 0;
12810 int distance = kMaxInt;
12811 while (!it.done()) {
12812 int statement_position = static_cast<int>(it.rinfo()->data());
12813 // Check if this break point is closer that what was previously found.
12814 if (source_position <= statement_position &&
12815 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012816 closest_pc =
12817 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012818 distance = statement_position - source_position;
12819 // Check whether we can't get any closer.
12820 if (distance == 0) break;
12821 }
12822 it.next();
12823 }
12824
12825 return Smi::FromInt(closest_pc);
12826}
12827
12828
ager@chromium.org357bf652010-04-12 11:30:10 +000012829// Calls specified function with or without entering the debugger.
12830// This is used in unit tests to run code as if debugger is entered or simply
12831// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012832RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012833 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012834 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012835 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12836 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12837
12838 Handle<Object> result;
12839 bool pending_exception;
12840 {
12841 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012842 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012843 &pending_exception);
12844 } else {
12845 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012846 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012847 &pending_exception);
12848 }
12849 }
12850 if (!pending_exception) {
12851 return *result;
12852 } else {
12853 return Failure::Exception();
12854 }
12855}
12856
12857
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012858// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012859RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012860 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012861 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012862 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12863 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012864 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012865}
12866
12867
12868// Performs a GC.
12869// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012870RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012871 isolate->heap()->CollectAllGarbage(true);
12872 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012873}
12874
12875
12876// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012877RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012878 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012879 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012880 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012881 }
12882 return Smi::FromInt(usage);
12883}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012884
12885
12886// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012887RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012888#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012889 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012890#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012891 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012892#endif
12893}
12894
12895
12896// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012897RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012898#ifdef LIVE_OBJECT_LIST
12899 return LiveObjectList::Capture();
12900#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012901 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012902#endif
12903}
12904
12905
12906// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012907RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012908#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012909 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012910 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012911 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012912#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012913 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012914#endif
12915}
12916
12917
12918// Generates the response to a debugger request for a dump of the objects
12919// contained in the difference between the captured live object lists
12920// specified by id1 and id2.
12921// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12922// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012923RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012924#ifdef LIVE_OBJECT_LIST
12925 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012926 CONVERT_SMI_ARG_CHECKED(id1, 0);
12927 CONVERT_SMI_ARG_CHECKED(id2, 1);
12928 CONVERT_SMI_ARG_CHECKED(start, 2);
12929 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012930 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12931 EnterDebugger enter_debugger;
12932 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12933#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012934 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012935#endif
12936}
12937
12938
12939// Gets the specified object as requested by the debugger.
12940// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012941RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012942#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012943 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012944 Object* result = LiveObjectList::GetObj(obj_id);
12945 return result;
12946#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012947 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012948#endif
12949}
12950
12951
12952// Gets the obj id for the specified address if valid.
12953// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012954RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012955#ifdef LIVE_OBJECT_LIST
12956 HandleScope scope;
12957 CONVERT_ARG_CHECKED(String, address, 0);
12958 Object* result = LiveObjectList::GetObjId(address);
12959 return result;
12960#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012961 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012962#endif
12963}
12964
12965
12966// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012967RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012968#ifdef LIVE_OBJECT_LIST
12969 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012970 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012971 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12972 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12973 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12974 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12975 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12976
12977 Handle<JSObject> instance_filter;
12978 if (args[1]->IsJSObject()) {
12979 instance_filter = args.at<JSObject>(1);
12980 }
12981 bool verbose = false;
12982 if (args[2]->IsBoolean()) {
12983 verbose = args[2]->IsTrue();
12984 }
12985 int start = 0;
12986 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012987 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012988 }
12989 int limit = Smi::kMaxValue;
12990 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012991 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012992 }
12993
12994 return LiveObjectList::GetObjRetainers(obj_id,
12995 instance_filter,
12996 verbose,
12997 start,
12998 limit,
12999 filter_obj);
13000#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013001 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013002#endif
13003}
13004
13005
13006// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013007RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013008#ifdef LIVE_OBJECT_LIST
13009 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013010 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13011 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013012 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13013
13014 Handle<JSObject> instance_filter;
13015 if (args[2]->IsJSObject()) {
13016 instance_filter = args.at<JSObject>(2);
13017 }
13018
13019 Object* result =
13020 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13021 return result;
13022#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013023 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013024#endif
13025}
13026
13027
13028// Generates the response to a debugger request for a list of all
13029// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013030RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013031#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013032 CONVERT_SMI_ARG_CHECKED(start, 0);
13033 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013034 return LiveObjectList::Info(start, count);
13035#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013036 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013037#endif
13038}
13039
13040
13041// Gets a dump of the specified object as requested by the debugger.
13042// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013043RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013044#ifdef LIVE_OBJECT_LIST
13045 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013046 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013047 Object* result = LiveObjectList::PrintObj(obj_id);
13048 return result;
13049#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013050 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013051#endif
13052}
13053
13054
13055// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013056RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013057#ifdef LIVE_OBJECT_LIST
13058 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013059 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013060#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013061 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013062#endif
13063}
13064
13065
13066// Generates the response to a debugger request for a summary of the types
13067// of objects in the difference between the captured live object lists
13068// specified by id1 and id2.
13069// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13070// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013071RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013072#ifdef LIVE_OBJECT_LIST
13073 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013074 CONVERT_SMI_ARG_CHECKED(id1, 0);
13075 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013076 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13077
13078 EnterDebugger enter_debugger;
13079 return LiveObjectList::Summarize(id1, id2, filter_obj);
13080#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013081 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013082#endif
13083}
13084
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013085#endif // ENABLE_DEBUGGER_SUPPORT
13086
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013088RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013089 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013090 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013091 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013092}
13093
13094
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013095RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013096 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013097 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013098 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013099}
13100
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013101
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013102// Finds the script object from the script data. NOTE: This operation uses
13103// heap traversal to find the function generated for the source position
13104// for the requested break point. For lazily compiled functions several heap
13105// traversals might be required rendering this operation as a rather slow
13106// operation. However for setting break points which is normally done through
13107// some kind of user interaction the performance is not crucial.
13108static Handle<Object> Runtime_GetScriptFromScriptName(
13109 Handle<String> script_name) {
13110 // Scan the heap for Script objects to find the script with the requested
13111 // script data.
13112 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013113 script_name->GetHeap()->EnsureHeapIsIterable();
13114 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013115 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013116 HeapObject* obj = NULL;
13117 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013118 // If a script is found check if it has the script data requested.
13119 if (obj->IsScript()) {
13120 if (Script::cast(obj)->name()->IsString()) {
13121 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13122 script = Handle<Script>(Script::cast(obj));
13123 }
13124 }
13125 }
13126 }
13127
13128 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013129 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013130
13131 // Return the script found.
13132 return GetScriptWrapper(script);
13133}
13134
13135
13136// Get the script object from script data. NOTE: Regarding performance
13137// see the NOTE for GetScriptFromScriptData.
13138// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013139RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013140 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013141
13142 ASSERT(args.length() == 1);
13143
13144 CONVERT_CHECKED(String, script_name, args[0]);
13145
13146 // Find the requested script.
13147 Handle<Object> result =
13148 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13149 return *result;
13150}
13151
13152
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013153// Determines whether the given stack frame should be displayed in
13154// a stack trace. The caller is the error constructor that asked
13155// for the stack trace to be collected. The first time a construct
13156// call to this function is encountered it is skipped. The seen_caller
13157// in/out parameter is used to remember if the caller has been seen
13158// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013159static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13160 Object* caller,
13161 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013162 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013163 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013164 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013165 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013166 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13167 Object* raw_fun = frame->function();
13168 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013169 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013170 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013171 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013172 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013173 *seen_caller = true;
13174 return false;
13175 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013176 // Skip all frames until we've seen the caller.
13177 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013178 // Also, skip non-visible built-in functions and any call with the builtins
13179 // object as receiver, so as to not reveal either the builtins object or
13180 // an internal function.
13181 // The --builtins-in-stack-traces command line flag allows including
13182 // internal call sites in the stack trace for debugging purposes.
13183 if (!FLAG_builtins_in_stack_traces) {
13184 JSFunction* fun = JSFunction::cast(raw_fun);
13185 if (frame->receiver()->IsJSBuiltinsObject() ||
13186 (fun->IsBuiltin() && !fun->shared()->native())) {
13187 return false;
13188 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013189 }
13190 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013191}
13192
13193
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013194// Collect the raw data for a stack trace. Returns an array of 4
13195// element segments each containing a receiver, function, code and
13196// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013197RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013198 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013199 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013200 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13201
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013202 HandleScope scope(isolate);
13203 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013204
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013205 limit = Max(limit, 0); // Ensure that limit is not negative.
13206 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013207 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013208 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013209
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013210 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013211 // If the caller parameter is a function we skip frames until we're
13212 // under it before starting to collect.
13213 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013214 int cursor = 0;
13215 int frames_seen = 0;
13216 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013217 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013218 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013219 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013220 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013221 // Set initial size to the maximum inlining level + 1 for the outermost
13222 // function.
13223 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013224 frame->Summarize(&frames);
13225 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013226 if (cursor + 4 > elements->length()) {
13227 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13228 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013229 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013230 for (int i = 0; i < cursor; i++) {
13231 new_elements->set(i, elements->get(i));
13232 }
13233 elements = new_elements;
13234 }
13235 ASSERT(cursor + 4 <= elements->length());
13236
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013237 Handle<Object> recv = frames[i].receiver();
13238 Handle<JSFunction> fun = frames[i].function();
13239 Handle<Code> code = frames[i].code();
13240 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013241 elements->set(cursor++, *recv);
13242 elements->set(cursor++, *fun);
13243 elements->set(cursor++, *code);
13244 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013245 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013246 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013247 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013248 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013249 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013250 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013251 return *result;
13252}
13253
13254
ager@chromium.org3811b432009-10-28 14:53:37 +000013255// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013256RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013257 ASSERT_EQ(args.length(), 0);
13258
13259 NoHandleAllocation ha;
13260
13261 const char* version_string = v8::V8::GetVersion();
13262
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013263 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13264 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013265}
13266
13267
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013268RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013269 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013270 OS::PrintError("abort: %s\n",
13271 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013272 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013273 OS::Abort();
13274 UNREACHABLE();
13275 return NULL;
13276}
13277
13278
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013279RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013280 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013281 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013282 Object* key = args[1];
13283
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013284 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013285 Object* o = cache->get(finger_index);
13286 if (o == key) {
13287 // The fastest case: hit the same place again.
13288 return cache->get(finger_index + 1);
13289 }
13290
13291 for (int i = finger_index - 2;
13292 i >= JSFunctionResultCache::kEntriesIndex;
13293 i -= 2) {
13294 o = cache->get(i);
13295 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013296 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013297 return cache->get(i + 1);
13298 }
13299 }
13300
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013301 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013302 ASSERT(size <= cache->length());
13303
13304 for (int i = size - 2; i > finger_index; i -= 2) {
13305 o = cache->get(i);
13306 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013307 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013308 return cache->get(i + 1);
13309 }
13310 }
13311
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013312 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013313 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013314
13315 Handle<JSFunctionResultCache> cache_handle(cache);
13316 Handle<Object> key_handle(key);
13317 Handle<Object> value;
13318 {
13319 Handle<JSFunction> factory(JSFunction::cast(
13320 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13321 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013322 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013323 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013324 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013325 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013326 value = Execution::Call(factory,
13327 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013328 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013329 argv,
13330 &pending_exception);
13331 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013332 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013333
13334#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013335 if (FLAG_verify_heap) {
13336 cache_handle->JSFunctionResultCacheVerify();
13337 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013338#endif
13339
13340 // Function invocation may have cleared the cache. Reread all the data.
13341 finger_index = cache_handle->finger_index();
13342 size = cache_handle->size();
13343
13344 // If we have spare room, put new data into it, otherwise evict post finger
13345 // entry which is likely to be the least recently used.
13346 int index = -1;
13347 if (size < cache_handle->length()) {
13348 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13349 index = size;
13350 } else {
13351 index = finger_index + JSFunctionResultCache::kEntrySize;
13352 if (index == cache_handle->length()) {
13353 index = JSFunctionResultCache::kEntriesIndex;
13354 }
13355 }
13356
13357 ASSERT(index % 2 == 0);
13358 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13359 ASSERT(index < cache_handle->length());
13360
13361 cache_handle->set(index, *key_handle);
13362 cache_handle->set(index + 1, *value);
13363 cache_handle->set_finger_index(index);
13364
13365#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013366 if (FLAG_verify_heap) {
13367 cache_handle->JSFunctionResultCacheVerify();
13368 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013369#endif
13370
13371 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013372}
13373
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013374
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013375RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013376 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013377 CONVERT_ARG_CHECKED(String, type, 0);
13378 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013379 return *isolate->factory()->NewJSMessageObject(
13380 type,
13381 arguments,
13382 0,
13383 0,
13384 isolate->factory()->undefined_value(),
13385 isolate->factory()->undefined_value(),
13386 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013387}
13388
13389
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013390RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013391 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13392 return message->type();
13393}
13394
13395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013396RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013397 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13398 return message->arguments();
13399}
13400
13401
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013402RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013403 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13404 return Smi::FromInt(message->start_position());
13405}
13406
13407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013408RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013409 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13410 return message->script();
13411}
13412
13413
kasper.lund44510672008-07-25 07:37:58 +000013414#ifdef DEBUG
13415// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13416// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013417RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013418 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013419 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013420#define COUNT_ENTRY(Name, argc, ressize) + 1
13421 int entry_count = 0
13422 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13423 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13424 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13425#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013426 Factory* factory = isolate->factory();
13427 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013428 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013429 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013430#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013431 { \
13432 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013433 Handle<String> name; \
13434 /* Inline runtime functions have an underscore in front of the name. */ \
13435 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013436 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013437 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13438 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013439 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013440 Vector<const char>(#Name, StrLength(#Name))); \
13441 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013442 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013443 pair_elements->set(0, *name); \
13444 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013445 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013446 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013447 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013448 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013449 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013450 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013451 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013452 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013453#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013454 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013455 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013456 return *result;
13457}
kasper.lund44510672008-07-25 07:37:58 +000013458#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013459
13460
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013461RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013462 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013463 CONVERT_CHECKED(String, format, args[0]);
13464 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013465 String::FlatContent format_content = format->GetFlatContent();
13466 RUNTIME_ASSERT(format_content.IsAscii());
13467 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013468 LOGGER->LogRuntime(chars, elms);
13469 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013470}
13471
13472
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013473RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013474 UNREACHABLE(); // implemented as macro in the parser
13475 return NULL;
13476}
13477
13478
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013479#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13480 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13481 CONVERT_CHECKED(JSObject, obj, args[0]); \
13482 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13483 }
13484
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013485ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013486ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13487ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13488ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13489ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13490ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13491ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13492ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13493ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13494ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13495ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13496ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13497ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13498ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13499
13500#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13501
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013502
13503RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13504 ASSERT(args.length() == 2);
13505 CONVERT_CHECKED(JSObject, obj1, args[0]);
13506 CONVERT_CHECKED(JSObject, obj2, args[1]);
13507 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13508}
13509
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013510// ----------------------------------------------------------------------------
13511// Implementation of Runtime
13512
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013513#define F(name, number_of_args, result_size) \
13514 { Runtime::k##name, Runtime::RUNTIME, #name, \
13515 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013516
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013517
13518#define I(name, number_of_args, result_size) \
13519 { Runtime::kInline##name, Runtime::INLINE, \
13520 "_" #name, NULL, number_of_args, result_size },
13521
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013522static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013523 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013524 INLINE_FUNCTION_LIST(I)
13525 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013526};
13527
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013528
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013529MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13530 Object* dictionary) {
13531 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013532 ASSERT(dictionary != NULL);
13533 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13534 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013535 Object* name_symbol;
13536 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013537 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013538 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13539 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013540 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013541 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13542 String::cast(name_symbol),
13543 Smi::FromInt(i),
13544 PropertyDetails(NONE, NORMAL));
13545 if (!maybe_dictionary->ToObject(&dictionary)) {
13546 // Non-recoverable failure. Calling code must restart heap
13547 // initialization.
13548 return maybe_dictionary;
13549 }
13550 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013551 }
13552 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013553}
13554
13555
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013556const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13557 Heap* heap = name->GetHeap();
13558 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013559 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013560 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013561 int function_index = Smi::cast(smi_index)->value();
13562 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013563 }
13564 return NULL;
13565}
13566
13567
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013568const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013569 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13570}
13571
13572
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013573void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013574 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013575 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013576 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013577 if (isolate->heap()->new_space()->AddFreshPage()) {
13578 return;
13579 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013580 // Try to do a garbage collection; ignore it if it fails. The C
13581 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013582 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013583 } else {
13584 // Handle last resort GC and make sure to allow future allocations
13585 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013586 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013587 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013588 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013589}
13590
13591
13592} } // namespace v8::internal